diff --git a/src/tools/qdoc/codemarker.cpp b/src/tools/qdoc/codemarker.cpp
index 9f22a287d20..fe0b366350a 100644
--- a/src/tools/qdoc/codemarker.cpp
+++ b/src/tools/qdoc/codemarker.cpp
@@ -649,7 +649,6 @@ QStringList CodeMarker::macRefsForNode(Node *node)
}
case Node::Namespace:
case Node::Fake:
- case Node::Target:
default:
return QStringList();
}
diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp
index 3e7d190fe43..aea8ed2119d 100644
--- a/src/tools/qdoc/cppcodemarker.cpp
+++ b/src/tools/qdoc/cppcodemarker.cpp
@@ -826,61 +826,38 @@ QList CppCodeMarker::sections(const InnerNode *inner,
return sections;
}
+/*!
+ Search the \a tree for a node named \a target
+ */
const Node *CppCodeMarker::resolveTarget(const QString& target,
const Tree* tree,
const Node* relative,
const Node* self)
{
+ const Node* node = 0;
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;
+ const FunctionNode* fn = tree->findFunctionNode(path, relative, Tree::SearchBaseClasses);
+ if (fn) {
+ /*
+ Why is this case not accepted?
+ */
+ if (fn->metaness() != FunctionNode::MacroWithoutParams)
+ node = fn;
+ }
}
else if (target.contains(QLatin1Char('#'))) {
- // ### this doesn't belong here; get rid of TargetNode hack
- int hashAt = target.indexOf(QLatin1Char('#'));
- 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();
- }
- }
+ // This error message is never printed; I think we can remove the case.
+ qDebug() << "qdoc: target case not handled:" << target;
}
else {
QStringList path = target.split("::");
- const Node *node;
- int flags = Tree::SearchBaseClasses |
- Tree::SearchEnumValues |
- Tree::NonFunction;
- if ((node = tree->findNode(path,
- relative,
- flags,
- self)))
- return node;
+ int flags = Tree::SearchBaseClasses | Tree::SearchEnumValues | Tree::NonFunction;
+ node = tree->findNode(path, relative, flags, self);
}
- return 0;
+ return node;
}
static const char * const typeTable[] = {
diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp
index a308da1f987..7dfb32bde04 100644
--- a/src/tools/qdoc/cppcodeparser.cpp
+++ b/src/tools/qdoc/cppcodeparser.cpp
@@ -79,7 +79,6 @@ QT_BEGIN_NAMESPACE
#define COMMAND_PROPERTY Doc::alias("property")
#define COMMAND_REIMP Doc::alias("reimp")
#define COMMAND_RELATES Doc::alias("relates")
-#define COMMAND_SERVICE Doc::alias("service")
#define COMMAND_STARTPAGE Doc::alias("startpage")
#define COMMAND_TYPEDEF Doc::alias("typedef")
#define COMMAND_VARIABLE Doc::alias("variable")
@@ -119,7 +118,7 @@ QStringList CppCodeParser::exampleDirs;
This is used for fuzzy matching only, which in turn is only used
for Qt Jambi.
*/
-static QString cleanType(const QString &type, const Tree *tree)
+static QString cleanType(const QString &type, Tree* tree)
{
QString result = type;
result.replace("qlonglong", "long long");
@@ -145,14 +144,13 @@ static QString cleanType(const QString &type, const Tree *tree)
while ((pos = result.indexOf(regExp, pos)) != -1) {
// we assume that the path for the associated enum
// is the same as for the flag typedef
- QStringList path = regExp.cap(2).split("::",
- QString::SkipEmptyParts);
- const EnumNode *enume = static_cast(
- tree->findNode(QStringList(path) << regExp.cap(3),
- Node::Enum));
- if (enume && enume->flagsType())
- result.replace(pos, regExp.matchedLength(),
- (QStringList(path) << enume->flagsType()->name()).join("::"));
+ QStringList path = regExp.cap(2).split("::", QString::SkipEmptyParts);
+ QStringList tmpPath = QStringList(path) << regExp.cap(3);
+ EnumNode* en = tree->findEnumNode(tmpPath);
+ if (en && en->flagsType()) {
+ tmpPath = QStringList(path) << en->flagsType()->name();
+ result.replace(pos, regExp.matchedLength(), tmpPath.join("::"));
+ }
++pos;
}
}
@@ -191,9 +189,12 @@ void CppCodeParser::initializeParser(const Config &config)
{
CodeParser::initializeParser(config);
+ /*
+ All these can appear in a C++ namespace. Don't add
+ anything that can't be in a C++ namespace.
+ */
nodeTypeMap.insert(COMMAND_NAMESPACE, Node::Namespace);
nodeTypeMap.insert(COMMAND_CLASS, Node::Class);
- nodeTypeMap.insert(COMMAND_SERVICE, Node::Class);
nodeTypeMap.insert(COMMAND_ENUM, Node::Enum);
nodeTypeMap.insert(COMMAND_TYPEDEF, Node::Typedef);
nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property);
@@ -306,7 +307,13 @@ void CppCodeParser::parseSourceFile(const Location& location,
Tokenizer fileTokenizer(fileLocation, in);
tokenizer = &fileTokenizer;
readToken();
- usedNamespaces.clear();
+
+ /*
+ The set of active namespaces is cleared before parsing
+ each source file. The word "source" here means cpp file.
+ */
+ activeNamespaces_.clear();
+
matchDocsAndStuff();
in.close();
}
@@ -403,14 +410,14 @@ const FunctionNode *CppCodeParser::findFunctionNode(const QString& synopsis,
This is necessary because Roberto's parser resolves typedefs.
*/
if (!func && fuzzy) {
- func = tre->findFunctionNode(parentPath +
+ func = tree_->findFunctionNode(parentPath +
QStringList(clone->name()),
relative,
flags);
if (!func && clone->name().contains('_')) {
QStringList path = parentPath;
path << clone->name().split('_');
- func = tre->findFunctionNode(path, relative, flags);
+ func = tree_->findFunctionNode(path, relative, flags);
}
if (func) {
@@ -512,7 +519,6 @@ QSet CppCodeParser::topicCommands()
<< COMMAND_NAMESPACE
<< COMMAND_PAGE
<< COMMAND_PROPERTY
- << COMMAND_SERVICE
<< COMMAND_TYPEDEF
<< COMMAND_VARIABLE
<< COMMAND_QMLCLASS
@@ -543,21 +549,21 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
doc.location().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN));
}
else {
- if (!usedNamespaces.isEmpty()) {
- foreach (const QString &usedNamespace, usedNamespaces) {
- QStringList newPath = usedNamespace.split("::") + parentPath;
- func = tre->findFunctionNode(newPath, clone);
+ if (!activeNamespaces_.isEmpty()) {
+ foreach (const QString& usedNamespace_, activeNamespaces_) {
+ QStringList newPath = usedNamespace_.split("::") + parentPath;
+ func = tree_->findFunctionNode(newPath, clone);
if (func)
break;
}
}
// Search the root namespace if no match was found.
if (func == 0)
- func = tre->findFunctionNode(parentPath, clone);
+ func = tree_->findFunctionNode(parentPath, clone);
if (func == 0) {
if (parentPath.isEmpty() && !lastPath.isEmpty())
- func = tre->findFunctionNode(lastPath, clone);
+ func = tree_->findFunctionNode(lastPath, clone);
if (func == 0) {
doc.location().warning(tr("Cannot find '%1' in '\\%2'")
.arg(clone->name() + "(...)")
@@ -589,7 +595,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
QStringList parentPath;
FunctionNode *func = 0;
- if (makeFunctionNode(arg, &parentPath, &func, tre->root())) {
+ if (makeFunctionNode(arg, &parentPath, &func, tree_->root())) {
if (!parentPath.isEmpty()) {
doc.location().warning(tr("Invalid syntax in '\\%1'")
.arg(COMMAND_MACRO));
@@ -610,7 +616,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return func;
}
else if (QRegExp("[A-Za-z_][A-Za-z0-9_]+").exactMatch(arg)) {
- func = new FunctionNode(tre->root(), arg);
+ func = new FunctionNode(tree_->root(), arg);
func->setAccess(Node::Public);
func->setLocation(doc.location());
func->setMetaness(FunctionNode::MacroWithoutParams);
@@ -624,25 +630,45 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
}
else if (nodeTypeMap.contains(command)) {
/*
- The command was neither "fn" nor "macro" .
+ We should only get in here if the command refers to
+ something that can appear in a C++ namespace,
+ i.e. a class, another namespace, an enum, a typedef,
+ a property or a variable. I think these are handled
+ this way to allow the writer to refer to the entity
+ without including the namespace qualifier.
*/
- // ### split(QLatin1Char(' ')) hack is there to support header file syntax
+ Node::Type type = nodeTypeMap[command];
+ Node::SubType subtype = Node::NoSubType;
+ if (type == Node::Fake)
+ subtype = Node::QmlClass;
+
QStringList paths = arg.split(QLatin1Char(' '));
QStringList path = paths[0].split("::");
Node *node = 0;
- if (!usedNamespaces.isEmpty()) {
- foreach (const QString &usedNamespace, usedNamespaces) {
- QStringList newPath = usedNamespace.split("::") + path;
- node = tre->findNode(newPath, nodeTypeMap[command]);
+
+ /*
+ If the command refers to something that can be in a
+ C++ namespace, search for it first in all the known
+ C++ namespaces.
+ */
+ if (!activeNamespaces_.isEmpty()) {
+ foreach (const QString& usedNamespace_, activeNamespaces_) {
+ QStringList newPath = usedNamespace_.split("::") + path;
+ node = tree_->findNodeByNameAndType(newPath, type, subtype, 0);
if (node) {
path = newPath;
break;
}
}
}
- // Search the root namespace if no match was found.
- if (node == 0)
- node = tre->findNode(path, nodeTypeMap[command]);
+
+ /*
+ If the node was not found in a C++ namespace, search
+ for it in the root namespace.
+ */
+ if (node == 0) {
+ node = tree_->findNodeByNameAndType(path, type, subtype, 0);
+ }
if (node == 0) {
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
@@ -650,63 +676,40 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
lastPath = path;
}
- else if (command == COMMAND_SERVICE) {
- // If the command is "\service", then we need to tag the
- // class with the actual service name.
- QStringList args = arg.split(QLatin1Char(' '));
- if (args.size() > 1) {
- ClassNode *cnode = static_cast(node);
- cnode->setServiceName(args[1]);
- cnode->setHideFromMainList(true);
- }
- }
else if (node->isInnerNode()) {
+ /*
+ This treets a class as a namespace.
+ */
if (path.size() > 1) {
path.pop_back();
- usedNamespaces.insert(path.join("::"));
+ QString ns = path.join("::");
+ activeNamespaces_.insert(ns);
}
}
-#if 0
- /*
- This code apparently does nothing. After further
- investigation to verify it is useless, it will
- be removed.
- */
- if (command == COMMAND_CLASS) {
- if (paths.size() > 1) {
- if (!paths[1].endsWith(".h")) {
- ClassNode* cnode = static_cast(node);
- cnode->setQmlElement(paths[1]);
- }
- }
- }
-#endif
return node;
}
else if (command == COMMAND_EXAMPLE) {
- if (Config::generateExamples) {
- ExampleNode* en = new ExampleNode(tre->root(), arg);
- createExampleFileNodes(en);
- return en;
- }
+ ExampleNode* en = new ExampleNode(tree_->root(), arg);
+ createExampleFileNodes(en);
+ return en;
}
else if (command == COMMAND_EXTERNALPAGE) {
- return new FakeNode(tre->root(), arg, Node::ExternalPage, Node::ArticlePage);
+ return new FakeNode(tree_->root(), arg, Node::ExternalPage, Node::ArticlePage);
}
else if (command == COMMAND_FILE) {
- return new FakeNode(tre->root(), arg, Node::File, Node::NoPageType);
+ return new FakeNode(tree_->root(), arg, Node::File, Node::NoPageType);
}
else if (command == COMMAND_GROUP) {
- return new FakeNode(tre->root(), arg, Node::Group, Node::OverviewPage);
+ return new FakeNode(tree_->root(), arg, Node::Group, Node::OverviewPage);
}
else if (command == COMMAND_HEADERFILE) {
- return new FakeNode(tre->root(), arg, Node::HeaderFile, Node::ApiPage);
+ return new FakeNode(tree_->root(), arg, Node::HeaderFile, Node::ApiPage);
}
else if (command == COMMAND_MODULE) {
- return new FakeNode(tre->root(), arg, Node::Module, Node::OverviewPage);
+ return new FakeNode(tree_->root(), arg, Node::Module, Node::OverviewPage);
}
else if (command == COMMAND_QMLMODULE) {
- return new FakeNode(tre->root(), arg, Node::QmlModule, Node::OverviewPage);
+ return new FakeNode(tree_->root(), arg, Node::QmlModule, Node::OverviewPage);
}
else if (command == COMMAND_PAGE) {
Node::PageType ptype = Node::ArticlePage;
@@ -740,30 +743,27 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
If there is no collision, just create a new Page
node and return that one.
*/
- NameCollisionNode* ncn = tre->checkForCollision(args[0]);
+ NameCollisionNode* ncn = tree_->checkForCollision(args[0]);
FakeNode* fn = 0;
if (ptype == Node::DitaMapPage)
- fn = new DitaMapNode(tre->root(), args[0]);
+ fn = new DitaMapNode(tree_->root(), args[0]);
else
- fn = new FakeNode(tre->root(), args[0], Node::Page, ptype);
+ fn = new FakeNode(tree_->root(), args[0], Node::Page, ptype);
if (ncn) {
ncn->addCollision(fn);
}
return fn;
}
else if (command == COMMAND_DITAMAP) {
- FakeNode* fn = new DitaMapNode(tre->root(), arg);
+ FakeNode* fn = new DitaMapNode(tree_->root(), arg);
return fn;
}
else if (command == COMMAND_QMLCLASS) {
- const ClassNode* classNode = 0;
+ ClassNode* classNode = 0;
QStringList names = arg.split(QLatin1Char(' '));
- if (names.size() > 1) {
- Node* n = tre->findNode(names[1].split("::"),Node::Class);
- if (n) {
- classNode = static_cast(n);
- }
- }
+ if (names.size() > 1)
+ classNode = tree_->findClassNode(names[1].split("::"));
+
/*
Search for a node with the same name. If there is one,
then there is a collision, so create a collision node
@@ -775,15 +775,14 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
If there is no collision, just create a new QML class
node and return that one.
*/
- NameCollisionNode* ncn = tre->checkForCollision(names[0]);
- QmlClassNode* qcn = new QmlClassNode(tre->root(), names[0], classNode);
- if (ncn) {
+ NameCollisionNode* ncn = tree_->checkForCollision(names[0]);
+ QmlClassNode* qcn = new QmlClassNode(tree_->root(), names[0], classNode);
+ if (ncn)
ncn->addCollision(qcn);
- }
return qcn;
}
else if (command == COMMAND_QMLBASICTYPE) {
- return new QmlBasicTypeNode(tre->root(), arg);
+ return new QmlBasicTypeNode(tree_->root(), arg);
}
else if ((command == COMMAND_QMLSIGNAL) ||
(command == COMMAND_QMLMETHOD) ||
@@ -793,7 +792,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
QString element;
QString type;
if (splitQmlMethodArg(doc,arg,type,module,element)) {
- QmlClassNode* qmlClass = tre->findQmlClassNode(module,element);
+ QmlClassNode* qmlClass = tree_->findQmlClassNode(module,element);
if (qmlClass) {
if (command == COMMAND_QMLSIGNAL)
return makeFunctionNode(doc,arg,qmlClass,Node::QmlSignal,false,COMMAND_QMLSIGNAL);
@@ -936,18 +935,18 @@ Node *CppCodeParser::processTopicCommandGroup(const Doc& doc,
bool attached = (command == COMMAND_QMLATTACHEDPROPERTY);
QStringList::ConstIterator arg = args.begin();
if (splitQmlPropertyArg(doc,(*arg),type,module,element,property)) {
- QmlClassNode* qmlClass = tre->findQmlClassNode(module,element);
+ QmlClassNode* qmlClass = tree_->findQmlClassNode(module,element);
if (qmlClass) {
qmlPropGroup = new QmlPropGroupNode(qmlClass,property,attached);
}
}
if (qmlPropGroup) {
- const ClassNode *correspondingClass = static_cast(qmlPropGroup->parent())->classNode();
+ ClassNode *correspondingClass = static_cast(qmlPropGroup->parent())->classNode();
QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlPropGroup,property,type,attached);
const PropertyNode *correspondingProperty = 0;
if (correspondingClass) {
- correspondingProperty = qmlPropNode->correspondingProperty(tre);
+ correspondingProperty = qmlPropNode->correspondingProperty(tree_);
}
if (correspondingProperty) {
bool writableList = type.startsWith("list") && correspondingProperty->dataType().endsWith('*');
@@ -1053,28 +1052,37 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else if (command == COMMAND_RELATES) {
- InnerNode *pseudoParent;
+ /*
+ Find the node that this node relates to.
+ */
+ Node* n = 0;
if (arg.startsWith(QLatin1Char('<')) || arg.startsWith('"')) {
- pseudoParent =
- static_cast(tre->findNode(QStringList(arg),
- Node::Fake));
+ /*
+ It should be a header file, I think.
+ */
+ n = tree_->findNodeByNameAndType(QStringList(arg), Node::Fake, Node::NoSubType, 0);
}
else {
+ /*
+ If it wasn't a file, it should be either a class or a namespace.
+ */
QStringList newPath = arg.split("::");
- pseudoParent =
- static_cast(tre->findNode(QStringList(newPath),
- Node::Class));
- if (!pseudoParent)
- pseudoParent =
- static_cast(tre->findNode(QStringList(newPath),
- Node::Namespace));
+ n = tree_->findClassNode(QStringList(newPath));
+ if (!n)
+ n = tree_->findNamespaceNode(QStringList(newPath));
}
- if (!pseudoParent) {
- doc.location().warning(tr("Cannot find '%1' in '\\%2'")
- .arg(arg).arg(COMMAND_RELATES));
+
+ if (!n) {
+ /*
+ Didn't ind it. Error...
+ */
+ doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES));
}
else {
- node->setRelates(pseudoParent);
+ /*
+ Found it. This node relates to it.
+ */
+ node->setRelates(static_cast(n));
}
}
else if (command == COMMAND_CONTENTSPAGE) {
@@ -1136,7 +1144,7 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else {
- processCommonMetaCommand(doc.location(),command,arg,node,tre);
+ processCommonMetaCommand(doc.location(),command,arg,node,tree_);
}
}
@@ -1165,7 +1173,7 @@ void CppCodeParser::processOtherMetaCommands(const Doc& doc, Node *node)
*/
void CppCodeParser::reset(Tree *tree)
{
- tre = tree;
+ tree_ = tree;
tokenizer = 0;
tok = 0;
access = Node::Public;
@@ -1691,7 +1699,7 @@ bool CppCodeParser::matchBaseSpecifier(ClassNode *classe, bool isClass)
if (!matchDataType(&baseClass))
return false;
- tre->addBaseClass(classe,
+ tree_->addBaseClass(classe,
access,
baseClass.toPath(),
baseClass.toString(),
@@ -1773,18 +1781,18 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent)
So far, so good. We have 'namespace Foo {'.
*/
QString namespaceName = previousLexeme();
- NamespaceNode *namespasse = 0;
+ NamespaceNode* ns = 0;
if (parent) {
- namespasse = static_cast(parent->findNode(namespaceName, Node::Namespace));
+ ns = static_cast(parent->findChildNodeByNameAndType(namespaceName, Node::Namespace));
}
- if (!namespasse) {
- namespasse = new NamespaceNode(parent, namespaceName);
- namespasse->setAccess(access);
- namespasse->setLocation(location());
+ if (!ns) {
+ ns = new NamespaceNode(parent, namespaceName);
+ ns->setAccess(access);
+ ns->setLocation(location());
}
readToken(); // skip '{'
- bool matched = matchDeclList(namespasse);
+ bool matched = matchDeclList(ns);
return matched && match(Tok_RightBrace);
}
@@ -1817,7 +1825,7 @@ bool CppCodeParser::matchUsingDecl()
/*
So far, so good. We have 'using namespace Foo;'.
*/
- usedNamespaces.insert(name);
+ activeNamespaces_.insert(name);
return true;
}
@@ -1915,10 +1923,10 @@ bool CppCodeParser::matchTypedefDecl(InnerNode *parent)
if (!match(Tok_Semicolon))
return false;
- if (parent && !parent->findNode(name, Node::Typedef)) {
- TypedefNode *typedeffe = new TypedefNode(parent, name);
- typedeffe->setAccess(access);
- typedeffe->setLocation(location());
+ if (parent && !parent->findChildNodeByNameAndType(name, Node::Typedef)) {
+ TypedefNode* td = new TypedefNode(parent, name);
+ td->setAccess(access);
+ td->setLocation(location());
}
return true;
}
@@ -1977,9 +1985,9 @@ bool CppCodeParser::matchProperty(InnerNode *parent)
}
if (key == "READ")
- tre->addPropertyFunction(property, value, PropertyNode::Getter);
+ tree_->addPropertyFunction(property, value, PropertyNode::Getter);
else if (key == "WRITE") {
- tre->addPropertyFunction(property, value, PropertyNode::Setter);
+ tree_->addPropertyFunction(property, value, PropertyNode::Setter);
property->setWritable(true);
}
else if (key == "STORED")
@@ -1996,9 +2004,9 @@ bool CppCodeParser::matchProperty(InnerNode *parent)
}
}
else if (key == "RESET")
- tre->addPropertyFunction(property, value, PropertyNode::Resetter);
+ tree_->addPropertyFunction(property, value, PropertyNode::Resetter);
else if (key == "NOTIFY") {
- tre->addPropertyFunction(property, value, PropertyNode::Notifier);
+ tree_->addPropertyFunction(property, value, PropertyNode::Notifier);
} else if (key == "REVISION") {
int revision;
bool ok;
@@ -2130,15 +2138,13 @@ bool CppCodeParser::matchDeclList(InnerNode *parent)
if (match(Tok_LeftParen) && match(Tok_Ident)) {
QString flagsType = previousLexeme();
if (match(Tok_Comma) && match(Tok_Ident)) {
- QString enumType = previousLexeme();
+ QString name = previousLexeme();
TypedefNode *flagsNode = new TypedefNode(parent, flagsType);
flagsNode->setAccess(access);
flagsNode->setLocation(location());
- EnumNode *enumNode =
- static_cast(parent->findNode(enumType,
- Node::Enum));
- if (enumNode)
- enumNode->setFlagsType(flagsNode);
+ EnumNode* en = static_cast(parent->findChildNodeByNameAndType(name, Node::Enum));
+ if (en)
+ en->setFlagsType(flagsNode);
}
}
match(Tok_RightParen);
@@ -2219,14 +2225,14 @@ bool CppCodeParser::matchDocsAndStuff()
FunctionNode *func = 0;
if (matchFunctionDecl(0, &parentPath, &clone)) {
- foreach (const QString &usedNamespace, usedNamespaces) {
- QStringList newPath = usedNamespace.split("::") + parentPath;
- func = tre->findFunctionNode(newPath, clone);
+ foreach (const QString& usedNamespace_, activeNamespaces_) {
+ QStringList newPath = usedNamespace_.split("::") + parentPath;
+ func = tree_->findFunctionNode(newPath, clone);
if (func)
break;
}
if (func == 0)
- func = tre->findFunctionNode(parentPath, clone);
+ func = tree_->findFunctionNode(parentPath, clone);
if (func) {
func->borrowParameterNames(clone);
@@ -2280,7 +2286,7 @@ bool CppCodeParser::matchDocsAndStuff()
if ((*n)->isInnerNode() &&
((InnerNode *)*n)->includes().isEmpty()) {
InnerNode *m = static_cast(*n);
- while (m->parent() != tre->root())
+ while (m->parent() != tree_->root())
m = m->parent();
if (m == *n)
((InnerNode *)*n)->addInclude((*n)->name());
@@ -2309,7 +2315,7 @@ bool CppCodeParser::matchDocsAndStuff()
Signals are implemented in uninteresting files
generated by moc.
*/
- node = tre->findFunctionNode(parentPath, clone);
+ node = tree_->findFunctionNode(parentPath, clone);
if (node != 0 && node->metaness() != FunctionNode::Signal)
node->setLocation(clone->location());
delete clone;
@@ -2421,7 +2427,7 @@ void CppCodeParser::instantiateIteratorMacro(const QString &container,
Tokenizer stringTokenizer(loc, latin1);
tokenizer = &stringTokenizer;
readToken();
- matchDeclList(tre->root());
+ matchDeclList(tree_->root());
}
void CppCodeParser::createExampleFileNodes(FakeNode *fake)
diff --git a/src/tools/qdoc/cppcodeparser.h b/src/tools/qdoc/cppcodeparser.h
index f33ff6430d9..74abb994d9a 100644
--- a/src/tools/qdoc/cppcodeparser.h
+++ b/src/tools/qdoc/cppcodeparser.h
@@ -165,7 +165,7 @@ private:
void createExampleFileNodes(FakeNode *fake);
QMap nodeTypeMap;
- Tree *tre;
+ Tree* tree_;
Tokenizer *tokenizer;
int tok;
Node::Access access;
@@ -179,7 +179,7 @@ private:
QString mutableSequentialIteratorDefinition;
QString associativeIteratorDefinition;
QString mutableAssociativeIteratorDefinition;
- QSet usedNamespaces;
+ QSet activeNamespaces_;
QMap sequentialIteratorClasses;
QMap mutableSequentialIteratorClasses;
QMap associativeIteratorClasses;
diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp
index 8fa7f938d1a..1458b640d18 100644
--- a/src/tools/qdoc/ditaxmlgenerator.cpp
+++ b/src/tools/qdoc/ditaxmlgenerator.cpp
@@ -418,7 +418,6 @@ DitaXmlGenerator::DitaXmlGenerator()
sectionNestingLevel(0),
tableColumnCount(0),
funcLeftParen("\\S(\\()"),
- tree_(0),
nodeTypeMaps(Node::LastType,0),
nodeSubtypeMaps(Node::LastSubtype,0),
pageTypeMaps(Node::OnBeyondZebra,0)
@@ -618,7 +617,7 @@ GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
This is where the DITA XML files are written.
\note The file is created in PageGenerator::generateTree().
*/
-void DitaXmlGenerator::generateTree(const Tree *tree)
+void DitaXmlGenerator::generateTree(Tree *tree)
{
tree_ = tree;
nonCompatClasses.clear();
@@ -638,6 +637,7 @@ void DitaXmlGenerator::generateTree(const Tree *tree)
findAllSince(tree->root());
Generator::generateTree(tree);
+ generateCollisionPages();
writeDitaMap(tree);
}
@@ -1269,19 +1269,15 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
const Node *node = 0;
QString myLink = getLink(atom, relative, marker, &node);
if (myLink.isEmpty()) {
- relative->doc().location().warning(tr("Can't link to '%1' in %2")
- .arg(atom->string())
- .arg(marker->plainFullName(relative)));
+ myLink = getCollisionLink(atom);
+ }
+ if (myLink.isEmpty()) {
+ relative->doc().location().warning(tr("Can't link to '%1'")
+ .arg(atom->string()));
}
else if (!inSectionHeading) {
beginLink(myLink);
}
-#if 0
- else {
- //xmlWriter().writeCharacters(atom->string());
- //qDebug() << "MYLINK:" << myLink << outFileName() << atom->string();
- }
-#endif
skipAhead = 1;
}
break;
@@ -1744,7 +1740,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
for marking up the code. I don't know what that means exactly.
*/
void
-DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* marker)
+DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
{
QList::ConstIterator s;
@@ -2143,8 +2139,8 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark
writeEndTag(); //
}
else if ((inner->type() == Node::Fake) && (inner->subType() == Node::QmlClass)) {
- const QmlClassNode* qcn = const_cast(static_cast(inner));
- const ClassNode* cn = qcn->classNode();
+ QmlClassNode* qcn = const_cast(static_cast(inner));
+ ClassNode* cn = qcn->classNode();
rawTitle = marker->plainName(inner);
fullTitle = marker->plainFullName(inner);
title = rawTitle + " Element";
@@ -2248,7 +2244,7 @@ void DitaXmlGenerator::writeXrefListItem(const QString& link, const QString& tex
Generate the DITA page for a qdoc file that doesn't map
to an underlying c++ file.
*/
-void DitaXmlGenerator::generateFakeNode(const FakeNode* fake, CodeMarker* marker)
+void DitaXmlGenerator::generateFakeNode(FakeNode* fake, CodeMarker* marker)
{
/*
If the fake node is a page node, and if the page type
@@ -2499,6 +2495,9 @@ void DitaXmlGenerator::generateHeader(const Node* node,
case Node::ExternalPage: // not used
outputclass = "externalpage";
break;
+ case Node::Collision:
+ outputclass = "collision";
+ break;
default:
outputclass = "page";
}
@@ -3302,16 +3301,11 @@ void DitaXmlGenerator::generateOverviewList(const Node* relative, CodeMarker* /*
else if (!isGroupPage) {
// If we encounter a page that belongs to a group then
// we add that page to the list for that group.
- const FakeNode* groupNode =
- static_cast(tree_->root()->findNode(group, Node::Fake));
- if (groupNode)
- fakeNodeMap[groupNode].insert(sortKey, fakeNode);
- //else
- // uncategorizedNodeMap.insert(sortKey, fakeNode);
- }// else
- // uncategorizedNodeMap.insert(sortKey, fakeNode);
- }// else
- // uncategorizedNodeMap.insert(sortKey, fakeNode);
+ const FakeNode* gn = tree_->findGroupNode(QStringList(group));
+ if (gn)
+ fakeNodeMap[gn].insert(sortKey, fakeNode);
+ }
+ }
}
}
@@ -3877,8 +3871,6 @@ QString DitaXmlGenerator::guidForNode(const Node* node)
return node->guid();
case Node::Variable:
return node->guid();
- case Node::Target:
- return node->guid();
}
return QString();
}
@@ -4143,7 +4135,7 @@ const Node* DitaXmlGenerator::findNodeForTarget(const QString& target,
node = relative;
}
else if (target.endsWith(".html")) {
- node = tree_->root()->findNode(target, Node::Fake);
+ node = tree_->root()->findChildNodeByNameAndType(target, Node::Fake);
}
else if (marker) {
node = marker->resolveTarget(target, tree_, relative);
@@ -4204,7 +4196,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom,
*node = relative;
}
else if (first.endsWith(".html")) {
- *node = tree_->root()->findNode(first, Node::Fake);
+ *node = tree_->root()->findChildNodeByNameAndType(first, Node::Fake);
}
else {
*node = marker->resolveTarget(first, tree_, relative);
@@ -4292,17 +4284,6 @@ QString DitaXmlGenerator::getLink(const Atom* atom,
return link;
}
-/*!
- This function can be called if getLink() returns an empty
- string.
- */
-QString DitaXmlGenerator::getDisambiguationLink(const Atom *, CodeMarker *)
-{
- qDebug() << "Unimplemented function called: "
- << "QString DitaXmlGenerator::getDisambiguationLink()";
- return QString();
-}
-
void DitaXmlGenerator::generateIndex(const QString& fileBase,
const QString& url,
const QString& title)
@@ -4419,19 +4400,19 @@ void DitaXmlGenerator::generateQmlSummary(const Section& section,
Outputs the DITA detailed documentation for a section
on a QML element reference page.
*/
-void DitaXmlGenerator::generateDetailedQmlMember(const Node* node,
+void DitaXmlGenerator::generateDetailedQmlMember(Node* node,
const InnerNode* relative,
CodeMarker* marker)
{
QString marked;
- const QmlPropertyNode* qpn = 0;
+ QmlPropertyNode* qpn = 0;
if (node->subType() == Node::QmlPropertyGroup) {
const QmlPropGroupNode* qpgn = static_cast(node);
NodeList::ConstIterator p = qpgn->childNodes().begin();
writeStartTag(DT_ul);
while (p != qpgn->childNodes().end()) {
if ((*p)->type() == Node::QmlProperty) {
- qpn = static_cast(*p);
+ qpn = static_cast(*p);
writeStartTag(DT_li);
writeGuidAttribute((Node*)qpn);
QString attr;
@@ -4457,7 +4438,7 @@ void DitaXmlGenerator::generateDetailedQmlMember(const Node* node,
writeEndTag(); //
}
else if (node->type() == Node::QmlProperty) {
- qpn = static_cast(node);
+ qpn = static_cast(node);
/*
If the QML property node has a single subproperty,
override, replace qpn with that override node and
@@ -4466,7 +4447,7 @@ void DitaXmlGenerator::generateDetailedQmlMember(const Node* node,
if (qpn->qmlPropNodes().size() == 1) {
Node* n = qpn->qmlPropNodes().at(0);
if (n->type() == Node::QmlProperty)
- qpn = static_cast(n);
+ qpn = static_cast(n);
}
/*
Now qpn either has no overrides, or it has more
@@ -4600,10 +4581,9 @@ void DitaXmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker*
If there is no class node, or if the class node status
is set to Node::Internal, do nothing.
*/
-void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn,
- CodeMarker* marker)
+void DitaXmlGenerator::generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker)
{
- const ClassNode* cn = qcn->classNode();
+ ClassNode* cn = qcn->classNode();
if (cn && (cn->status() != Node::Internal)) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","instantiates");
@@ -4631,8 +4611,7 @@ void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn,
If there is no QML element, or if the class node status
is set to Node::Internal, do nothing.
*/
-void DitaXmlGenerator::generateInstantiatedBy(const ClassNode* cn,
- CodeMarker* marker)
+void DitaXmlGenerator::generateInstantiatedBy(ClassNode* cn, CodeMarker* marker)
{
if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) {
const QmlClassNode* qcn = cn->qmlElement();
@@ -5628,13 +5607,13 @@ void DitaXmlGenerator::writeNestedClasses(const Section& s,
Recursive writing of DITA XML files from the root \a node.
*/
void
-DitaXmlGenerator::generateInnerNode(const InnerNode* node)
+DitaXmlGenerator::generateInnerNode(InnerNode* node)
{
if (!node->url().isNull())
return;
if (node->type() == Node::Fake) {
- const FakeNode *fakeNode = static_cast(node);
+ FakeNode* fakeNode = static_cast(node);
if (fakeNode->subType() == Node::ExternalPage)
return;
if (fakeNode->subType() == Node::Image)
@@ -5653,27 +5632,38 @@ DitaXmlGenerator::generateInnerNode(const InnerNode* node)
CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
if (node->parent() != 0) {
- if (!node->name().endsWith(".ditamap"))
- beginSubPage(node, fileName(node));
- if (node->type() == Node::Namespace || node->type() == Node::Class) {
- generateClassLikeNode(node, marker);
+ /*
+ Skip name collision nodes here and process them
+ later in generateCollisionPages(). Each one is
+ appended to a list for later.
+ */
+ if ((node->type() == Node::Fake) && (node->subType() == Node::Collision)) {
+ NameCollisionNode* ncn = static_cast(node);
+ collisionNodes.append(const_cast(ncn));
}
- else if (node->type() == Node::Fake) {
- if (node->subType() == Node::HeaderFile)
+ else {
+ if (!node->name().endsWith(".ditamap"))
+ beginSubPage(node, fileName(node));
+ if (node->type() == Node::Namespace || node->type() == Node::Class) {
generateClassLikeNode(node, marker);
- else if (node->subType() == Node::QmlClass)
- generateClassLikeNode(node, marker);
- else
- generateFakeNode(static_cast(node), marker);
+ }
+ else if (node->type() == Node::Fake) {
+ if (node->subType() == Node::HeaderFile)
+ generateClassLikeNode(node, marker);
+ else if (node->subType() == Node::QmlClass)
+ generateClassLikeNode(node, marker);
+ else
+ generateFakeNode(static_cast(node), marker);
+ }
+ if (!node->name().endsWith(".ditamap"))
+ endSubPage();
}
- if (!node->name().endsWith(".ditamap"))
- endSubPage();
}
NodeList::ConstIterator c = node->childNodes().begin();
while (c != node->childNodes().end()) {
if ((*c)->isInnerNode() && (*c)->access() != Node::Private)
- generateInnerNode((const InnerNode*) *c);
+ generateInnerNode((InnerNode*)*c);
++c;
}
}
@@ -5819,8 +5809,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
break;
case Node::Variable:
break;
- case Node::Target:
- break;
case Node::QmlProperty:
break;
case Node::QmlSignal:
@@ -5840,7 +5828,7 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
Creates the DITA map for the qdoc run. The map is written
to the file \e{qt.ditamap" in the DITA XML output directory.
*/
-void DitaXmlGenerator::writeDitaMap(const Tree *tree)
+void DitaXmlGenerator::writeDitaMap(Tree *tree)
{
QString doctype;
@@ -6374,5 +6362,125 @@ QString DitaXmlGenerator::stripMarkup(const QString& src) const
return text;
}
+/*!
+ We delayed generation of the collision pages until now, after
+ all the other pages have been generated. We do this because we might
+ encounter a link command that tries to link to a target on a QML
+ type page, but the link doesn't specify the module identifer
+ for the QML type, and the QML type name without a module
+ identifier is ambiguous. When such a link is found, qdoc can't find
+ the target, so it appends the target to the NameCollisionNode. After
+ the tree has been traversed and all these ambiguous links have been
+ added to the name collision nodes, this function is called. The list
+ of collision nodes is traversed here, and the collision page for
+ each collision is generated. The collision page will not only
+ disambiguate links to the QML type pages, but it will also disambiguate
+ links to properties, section headers, etc.
+ */
+void DitaXmlGenerator::generateCollisionPages()
+{
+ if (collisionNodes.isEmpty())
+ return;
+
+ for (int i=0; ichildNodes();
+ if (!nl.isEmpty()) {
+ NodeList::ConstIterator it = nl.begin();
+ while (it != nl.end()) {
+ if (!(*it)->isInternal())
+ collisions.append(*it);
+ ++it;
+ }
+ }
+ if (collisions.size() <= 1)
+ continue;
+
+ ncn->clearCurrentChild();
+ beginSubPage(ncn, Generator::fileName(ncn));
+ QString fullTitle = ncn->fullTitle();
+ QString ditaTitle = fullTitle;
+ CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath());
+ if (ncn->isQmlNode()) {
+ // Replace the marker with a QML code marker.
+ if (ncn->isQmlNode())
+ marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
+ }
+
+ generateHeader(ncn, ditaTitle);
+ writeProlog(ncn);
+ writeStartTag(DT_body);
+ enterSection(QString(),QString());
+
+ NodeMap nm;
+ for (int i=0; iqmlModuleIdentifier().isEmpty())
+ t = n->qmlModuleIdentifier() + " ";
+ t += protectEnc(fullTitle);
+ nm.insertMulti(t,n);
+ }
+ generateAnnotatedList(ncn, marker, nm);
+
+ QList targets;
+ if (!ncn->linkTargets().isEmpty()) {
+ QMap::ConstIterator t = ncn->linkTargets().begin();
+ while (t != ncn->linkTargets().end()) {
+ int count = 0;
+ for (int i=0; i(collisions.at(i));
+ if (n->findChildNodeByName(t.key())) {
+ ++count;
+ if (count > 1) {
+ targets.append(t.key());
+ break;
+ }
+ }
+ }
+ ++t;
+ }
+ }
+ if (!targets.isEmpty()) {
+ QList::ConstIterator t = targets.begin();
+ while (t != targets.end()) {
+ writeStartTag(DT_p);
+ writeGuidAttribute(Doc::canonicalTitle(*t));
+ xmlWriter().writeAttribute("outputclass","h2");
+ writeCharacters(protectEnc(*t));
+ writeEndTag(); //
+ writeStartTag(DT_ul);
+ for (int i=0; i(collisions.at(i));
+ Node* p = n->findChildNodeByName(*t);
+ if (p) {
+ QString link = linkForNode(p,0);
+ QString label;
+ if (!n->qmlModuleIdentifier().isEmpty())
+ label = n->qmlModuleIdentifier() + "::";
+ label += n->name() + "::" + p->name();
+ writeStartTag(DT_li);
+ writeStartTag(DT_xref);
+ xmlWriter().writeAttribute("href", link);
+ writeCharacters(protectEnc(label));
+ writeEndTag(); //
+ writeEndTag(); //
+ }
+ }
+ writeEndTag(); //
+ ++t;
+ }
+ }
+ leaveSection(); //
+ writeEndTag(); //