qdoc: \l{Qt::Window} links to the wrong page

kThis update fixes a bug introduced by the extensive changes
for QTBUG-35377. The name Qt represents two namespaces, one
in C++ and one in QML. The name "Window" is used in both of
them, so the link \l{Qt::Window} would cause a collision in
the single tree qdoc. In the multiple tree qdoc, there is
no collision, but in this case the link should have gone to
the C++ page and it went to the QML page instead. The fix
involved correcting the way qdoc searches for link targets.

Task-number: QTBUG-37633
Change-Id: Ib9b209eced937a0be0d3299f300ebf22b2776012
Reviewed-by: Martin Smith <martin.smith@digia.com>
This commit is contained in:
Martin Smith 2014-03-19 15:12:07 +01:00 committed by The Qt Project
parent 900c150a07
commit 2ea15849a0
6 changed files with 219 additions and 228 deletions

View File

@ -3389,68 +3389,71 @@ void DitaXmlGenerator::writeText(const QString& markedCode, const Node* relative
for (int k = 0; k != 6; ++k) {
if (parseArg(src, markTags[k], &i, n, &arg, &par1)) {
const Node* n = 0;
if (k == 0) { // <@link>
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
n = CodeMarker::nodeForString(par1.toString());
QString link = linkForNode(n, relative);
addLink(link, arg);
}
else if (k == 4) { // <@param>
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
writeStartTag(DT_i);
//writeCharacters(" " + arg.toString());
writeCharacters(arg.toString());
writeEndTag(); // </i>
}
else if (k == 5) { // <@extra>
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
writeStartTag(DT_tt);
writeCharacters(arg.toString());
writeEndTag(); // </tt>
}
else {
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
par1 = QStringRef();
QString link;
n = qdb_->resolveTarget(arg.toString(), relative);
if (n && n->subType() == Node::QmlBasicType) {
if (relative && relative->subType() == Node::QmlClass) {
link = linkForNode(n,relative);
addLink(link, arg);
switch (k) {
case 0: // <@link>
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
else {
writeCharacters(arg.toString());
n = CodeMarker::nodeForString(par1.toString());
addLink(linkForNode(n, relative), arg);
break;
case 4: // <@param>
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
}
else {
// (zzz) Is this correct for all cases?
link = linkForNode(n,relative);
addLink(link, arg);
}
}
writeStartTag(DT_i);
//writeCharacters(" " + arg.toString());
writeCharacters(arg.toString());
writeEndTag(); // </i>
break;
case 5: // <@extra>
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
writeStartTag(DT_tt);
writeCharacters(arg.toString());
writeEndTag(); // </tt>
break;
case 3:
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
par1 = QStringRef();
n = qdb_->resolveFunctionTarget(arg.toString(), relative);
addLink(linkForNode(n, relative), arg);
break;
case 1:
case 2:
default:
if (!text.isEmpty()) {
writeCharacters(text);
text.clear();
}
par1 = QStringRef();
n = qdb_->resolveType(arg.toString(), relative);
if (n && n->subType() == Node::QmlBasicType) {
if (relative && relative->subType() == Node::QmlClass)
addLink(linkForNode(n, relative), arg);
else
writeCharacters(arg.toString());
}
else
addLink(linkForNode(n, relative), arg); // (zzz) Is this correct for all cases?
break;
} // switch
break;
}
}
}
else {
else
text += src.at(i++);
}
}
if (!text.isEmpty()) {
if (!text.isEmpty())
writeCharacters(text);
}
}
void DitaXmlGenerator::generateLink(const Atom* atom, CodeMarker* marker)
@ -3830,18 +3833,18 @@ QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const
QString ref;
QString first = path.first().trimmed();
if (first.isEmpty()) {
if (first.isEmpty())
*node = relative;
}
else if (first.endsWith(".html")) {
else if (first.endsWith(".html"))
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
}
else if (first.endsWith("()")) // The target is a C++ function or QML method.
*node = qdb_->resolveFunctionTarget(first, relative);
else {
*node = qdb_->resolveTarget(first, relative);
if (!(*node))
*node = qdb_->findDocNodeByTitle(first);
if (!*node)
*node = qdb_->findDocNodeByTitle(first, relative);
if (!*node)
*node = qdb_->findUnambiguousTarget(first, ref, relative);
*node = qdb_->findUnambiguousTarget(first, ref);
}
if (*node) {
@ -4601,7 +4604,7 @@ void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, const InnerNode* par
}
i += 2;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
const Node* tn = qdb_->resolveTarget(arg.toString(), parent);
const Node* tn = qdb_->resolveType(arg.toString(), parent);
if (tn) {
//Do not generate a link from a C++ function to a QML Basic Type (such as int)
if (n->type() == Node::Function && tn->subType() == Node::QmlBasicType)

View File

@ -320,6 +320,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
if (!inLink_ && !inContents_ && !inSectionHeading_) {
const Node *node = 0;
QString link = getLink(atom, relative, &node);
QDocDatabase::debug = false;
if (!link.isEmpty()) {
beginLink(link, node, relative);
generateLink(atom, marker);
@ -3188,7 +3189,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
const Node* n = qdb_->resolveTarget(par1.toString(), relative);
const Node* n = qdb_->resolveFunctionTarget(par1.toString(), relative);
QString link = linkForNode(n, relative);
addLink(link, arg, &html);
par1 = QStringRef();
@ -3228,20 +3229,18 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
}
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
const Node* n = qdb_->resolveTarget(arg.toString(), relative);
addLink(linkForNode(n,relative), arg, &html);
if (arg.at(0) == QChar('&'))
html += arg.toString();
else {
// zzz resolveClassTarget()
const Node* n = qdb_->resolveTarget(arg.toString(), relative);
if (n)
addLink(linkForNode(n,relative), arg, &html);
else
html += arg.toString();
}
handled = true;
}
#if 0
// Apparently, this clause was never used.
// <@func> is taken out above.
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
const Node* n = qdb_->resolveTarget(arg.toString(), relative);
addLink(linkForNode(n,relative), arg, &html);
handled = true;
}
#endif
if (!handled) {
html += charLangle;
html += charAt;
@ -3763,45 +3762,35 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
*node = 0;
inObsoleteLink = false;
if (atom->string().contains(QLatin1Char(':')) &&
(atom->string().startsWith("file:")
|| atom->string().startsWith("http:")
|| atom->string().startsWith("https:")
|| atom->string().startsWith("ftp:")
|| atom->string().startsWith("mailto:"))) {
link = atom->string();
if (atom->string().contains(QLatin1Char(':')) && (atom->string().startsWith("file:") ||
atom->string().startsWith("http:") ||
atom->string().startsWith("https:") ||
atom->string().startsWith("ftp:") ||
atom->string().startsWith("mailto:"))) {
link = atom->string(); // It's some kind of protocol.
}
else {
QStringList path;
if (atom->string().contains('#')) {
path = atom->string().split('#');
}
else {
path.append(atom->string());
}
if (atom->string().contains('#'))
path = atom->string().split('#'); // The target is in the html file.
else
path.append(atom->string()); // It's a general case target.
QString ref;
QString first = path.first().trimmed();
if (first.isEmpty()) {
if (first.isEmpty())
*node = relative;
}
else if (first.endsWith(".html")) {
/*
This is not a recursive search. That's ok in
this case, because we are searching for a page
node, which must be a direct child of the tree
root.
*/
else if (first.endsWith(".html")) // The target is an html file.
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
else if (first.endsWith("()")) { // The target is a C++ function or QML method.
*node = qdb_->resolveFunctionTarget(first, relative);
}
else {
*node = qdb_->resolveTarget(first, relative);
if (!(*node))
*node = qdb_->resolveTarget(first, relative);
if (!(*node))
*node = qdb_->findDocNodeByTitle(first, relative);
*node = qdb_->findDocNodeByTitle(first);
if (!(*node)) {
*node = qdb_->findUnambiguousTarget(first, ref, relative);
*node = qdb_->findUnambiguousTarget(first, ref);
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
QString final = (*node)->url() + "#" + ref;
return final;

View File

@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE
static NodeMap emptyNodeMap_;
static NodeMultiMap emptyNodeMultiMap_;
bool QDocDatabase::debug = false;
/*! \class QDocForest
This class manages a collection of trees. Each tree is an
@ -368,38 +369,30 @@ void QDocForest::newPrimaryTree(const QString& module)
}
/*!
Searches the Tree \a t for a node named \a target and returns
Searches the trees for a node named \a target and returns
a pointer to it if found. The \a relative node is the starting
point, but it only makes sense in the primary tree. Therefore,
when this function is called with \a t being an index tree,
\a relative is 0. When relative is 0, the root node of \a t is
the starting point.
point, but it only makes sense in the primary tree, which is
searched first. After the primary tree is searched, \a relative
is set to 0 for searching the index trees. When relative is 0,
the root node of the index tree is the starting point.
*/
const Node* QDocForest::resolveTargetHelper(const QString& target,
const Node* relative,
Tree* t)
const Node* QDocForest::resolveTarget(const QString& target, const Node* relative)
{
const Node* node = 0;
if (target.endsWith("()")) {
QString funcName = target;
funcName.chop(2);
QStringList path = funcName.split("::");
const FunctionNode* fn = t->findFunctionNode(path, relative, SearchBaseClasses);
if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
node = fn;
QStringList path = target.split("::");
int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
foreach (Tree* t, searchOrder()) {
const Node* n = t->findNode(path, relative, flags);
if (n)
return n;
#if 0
n = t->findDocNodeByTitle(target);
if (n)
return n;
#endif
relative = 0;
}
else {
QStringList path = target.split("::");
int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
node = t->findNode(path, relative, flags);
if (!node) {
QStringList path = target.split("::");
const FunctionNode* fn = t->findFunctionNode(path, relative, SearchBaseClasses);
if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
node = fn;
}
}
return node;
return 0;
}
/*!
@ -1356,7 +1349,7 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r
else {
node = resolveTarget(target, relative);
if (!node)
node = findDocNodeByTitle(target, relative);
node = findDocNodeByTitle(target);
}
return node;
}

View File

@ -89,11 +89,11 @@ class QDocForest
const Node* findNode(const QStringList& path, const Node* relative, int findFlags) {
foreach (Tree* t, searchOrder()) {
const Node* n = t->findNode(path, relative, findFlags);
if (n) return n;
if (n)
return n;
relative = 0;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 1" << path;
//qDebug() << "FAILED SEARCH 1" << path;
return 0;
}
@ -103,55 +103,53 @@ class QDocForest
bool acceptCollision = false) {
foreach (Tree* t, searchOrder()) {
Node* n = t->findNodeByNameAndType(path, type, subtype, acceptCollision);
if (n) return n;
if (n)
return n;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 2" << path << type << subtype;
//qDebug() << "FAILED SEARCH 2" << path << type << subtype;
return 0;
}
ClassNode* findClassNode(const QStringList& path) {
foreach (Tree* t, searchOrder()) {
ClassNode* n = t->findClassNode(path);
if (n) return n;
if (n)
return n;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 3" << path;
//qDebug() << "FAILED SEARCH 3" << path;
return 0;
}
InnerNode* findRelatesNode(const QStringList& path) {
foreach (Tree* t, searchOrder()) {
InnerNode* n = t->findRelatesNode(path);
if (n) return n;
if (n)
return n;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 4" << path;
//qDebug() << "FAILED SEARCH 4" << path;
return 0;
}
const Node* resolveTarget(const QString& target, const Node* relative) {
const Node* r = relative;
const Node* resolveFunctionTarget(const QString& target, const Node* relative) {
foreach (Tree* t, searchOrder()) {
const Node* n = resolveTargetHelper(target, relative, t);
if (n) return n;
const Node* n = t->resolveFunctionTarget(target, relative);
if (n)
return n;
relative = 0;
}
if (Config::debug_) {
qDebug() << "FAILED SEARCH 6" << target << r;
}
return 0;
}
const Node* resolveTarget(const QString& target, const Node* relative);
const Node* resolveType(const QStringList& path, const Node* relative)
{
foreach (Tree* t, searchOrder()) {
const Node* n = resolveTypeHelper(path, relative, t);
if (n) return n;
if (n)
return n;
relative = 0;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 5" << path;
//qDebug() << "FAILED SEARCH 5" << path;
return 0;
}
@ -159,32 +157,32 @@ class QDocForest
{
foreach (Tree* t, searchOrder()) {
QString ref = t->findTarget(target, node);
if (!ref.isEmpty()) return ref;
if (!ref.isEmpty())
return ref;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 7" << target;
//qDebug() << "FAILED SEARCH 7" << target;
return QString();
}
const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative)
const Node* findUnambiguousTarget(const QString& target, QString& ref)
{
foreach (Tree* t, searchOrder()) {
const Node* n = t->findUnambiguousTarget(target, ref, relative);
if (n) return n;
const Node* n = t->findUnambiguousTarget(target, ref);
if (n)
return n;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 8" << target;
//qDebug() << "FAILED SEARCH 8" << target;
return 0;
}
const DocNode* findDocNodeByTitle(const QString& title, const Node* relative)
const DocNode* findDocNodeByTitle(const QString& title)
{
foreach (Tree* t, searchOrder()) {
const DocNode* n = t->findDocNodeByTitle(title, relative);
if (n) return n;
const DocNode* n = t->findDocNodeByTitle(title);
if (n)
return n;
}
if (Config::debug_)
qDebug() << "FAILED SEARCH 9" << title;
//qDebug() << "FAILED SEARCH 9" << title;
return 0;
}
@ -192,7 +190,8 @@ class QDocForest
{
foreach (Tree* t, searchOrder()) {
QmlClassNode* qcn = t->lookupQmlType(name);
if (qcn) return qcn;
if (qcn)
return qcn;
}
return 0;
}
@ -209,7 +208,6 @@ class QDocForest
private:
void newPrimaryTree(const QString& module);
NamespaceNode* newIndexTree(const QString& module);
const Node* resolveTargetHelper(const QString& target, const Node* relative, Tree* t);
const Node* resolveTypeHelper(const QStringList& path, const Node* relative, Tree* t);
private:
@ -329,13 +327,16 @@ class QDocDatabase
const Node* resolveTarget(const QString& target, const Node* relative) {
return forest_.resolveTarget(target, relative);
}
const Node* resolveFunctionTarget(const QString& target, const Node* relative) {
return forest_.resolveFunctionTarget(target, relative);
}
const Node* resolveType(const QString& type, const Node* relative);
const Node* findNodeForTarget(const QString& target, const Node* relative);
const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) {
return forest_.findDocNodeByTitle(title, relative);
const DocNode* findDocNodeByTitle(const QString& title) {
return forest_.findDocNodeByTitle(title);
}
const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative) {
return forest_.findUnambiguousTarget(target, ref, relative);
const Node* findUnambiguousTarget(const QString& target, QString& ref) {
return forest_.findUnambiguousTarget(target, ref);
}
Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
return forest_.findNodeByNameAndType(path, type, subtype, false);
@ -389,6 +390,9 @@ class QDocDatabase
QDocDatabase& operator=(QDocDatabase const& );
Tree* primaryTree() { return forest_.primaryTree(); }
public:
static bool debug;
private:
static QDocDatabase* qdocDB_;
static NodeMap typeNodeMap_;

View File

@ -220,17 +220,23 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (!relative)
relative = root();
/*
If the path contains two double colons ("::"), check
first to see if it is a reference to a QML method. If
it is a reference to a QML method, first look up the
QML class node in the QML module map.
*/
if (path.size() == 3 && !path[0].isEmpty()) {
QmlClassNode* qcn = qdb_->findQmlType(path[0], path[1]);
if (qcn) {
return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2]));
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (!qcn) {
QStringList p(path[1]);
Node* n = findNodeByNameAndType(p, Node::Document, Node::QmlClass, true);
if (n) {
if (n->subType() == Node::QmlClass)
qcn = static_cast<QmlClassNode*>(n);
else if (n->subType() == Node::Collision) {
NameCollisionNode* ncn;
ncn = static_cast<NameCollisionNode*>(n);
qcn = static_cast<QmlClassNode*>(ncn->findAny(Node::Document, Node::QmlClass));
}
}
}
if (qcn)
return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2]));
}
do {
@ -555,7 +561,7 @@ NodeList Tree::allBaseClasses(const ClassNode* classNode) const
Node* Tree::findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
bool acceptCollision)
bool acceptCollision) const
{
Node* result = findNodeRecursive(path, 0, root(), type, subtype, acceptCollision);
return result;
@ -581,22 +587,23 @@ Node* Tree::findNodeByNameAndType(const QStringList& path,
*/
Node* Tree::findNodeRecursive(const QStringList& path,
int pathIndex,
Node* start,
const Node* start,
Node::Type type,
Node::SubType subtype,
bool acceptCollision) const
{
if (!start || path.isEmpty())
return 0; // no place to start, or nothing to search for.
Node* node = const_cast<Node*>(start);
if (start->isLeaf()) {
if (pathIndex >= path.size())
return start; // found a match.
return node; // found a match.
return 0; // premature leaf
}
if (pathIndex >= path.size())
return 0; // end of search path.
InnerNode* current = static_cast<InnerNode*>(start);
InnerNode* current = static_cast<InnerNode*>(node);
const NodeList& children = current->childNodes();
const QString& name = path.at(pathIndex);
for (int i=0; i<children.size(); ++i) {
@ -714,7 +721,9 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
QML node.
*/
const Node* n = findNode(path, current, findFlags, false);
return (n ? n : findNode(path, current, findFlags, true));
if (n)
return n;
return findNode(path, current, findFlags, true);
}
/*!
@ -745,7 +754,7 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
class node.
*/
if (qml && path.size() >= 2 && !path[0].isEmpty()) {
QmlClassNode* qcn = qdb_->findQmlType(path[0], path[1]);
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (qcn) {
node = qcn;
if (path.size() == 2)
@ -759,17 +768,18 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
break;
const Node* next = static_cast<const InnerNode*>(node)->findChildNode(path.at(i), qml);
if (!next && (findFlags & SearchEnumValues) && i == path.size()-1)
if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) {
next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
}
if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const Node* baseClass, baseClasses) {
next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i));
if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i));
if (next)
if (next) {
break;
}
}
}
node = next;
@ -903,7 +913,7 @@ void Tree::resolveTargets(InnerNode* root)
finds one, it sets \a ref and returns the found node.
*/
const Node*
Tree::findUnambiguousTarget(const QString& target, QString& ref, const Node* relative)
Tree::findUnambiguousTarget(const QString& target, QString& ref)
{
TargetRec bestTarget;
int numBestTargets = 0;
@ -932,15 +942,15 @@ Tree::findUnambiguousTarget(const QString& target, QString& ref, const Node* rel
return bestTarget.node_;
}
else if (bestTargetList.size() > 1) {
if (relative && !relative->qmlModuleName().isEmpty()) {
for (int i=0; i<bestTargetList.size(); ++i) {
const Node* n = bestTargetList.at(i).node_;
if (n && relative->qmlModuleName() == n->qmlModuleName()) {
ref = bestTargetList.at(i).ref_;
return n;
}
}
#if 0
qDebug() << "TARGET:" << target << numBestTargets;
for (int i=0; i<bestTargetList.size(); ++i) {
const Node* n = bestTargetList.at(i).node_;
qDebug() << " " << n->name() << n->title();
}
#endif
ref = bestTargetList.at(0).ref_;
return bestTargetList.at(0).node_;
}
}
ref.clear();
@ -949,36 +959,12 @@ Tree::findUnambiguousTarget(const QString& target, QString& ref, const Node* rel
/*!
This function searches for a node with the specified \a title.
If \a relative node is provided, it is used to disambiguate if
it has a QML module identifier.
*/
const DocNode* Tree::findDocNodeByTitle(const QString& title, const Node* relative) const
const DocNode* Tree::findDocNodeByTitle(const QString& title) const
{
QString key = Doc::canonicalTitle(title);
DocNodeMultiMap::const_iterator i = docNodesByTitle_.constFind(key);
if (i != docNodesByTitle_.constEnd()) {
if (relative && !relative->qmlModuleName().isEmpty()) {
const DocNode* dn = i.value();
InnerNode* parent = dn->parent();
if (parent && parent->type() == Node::Document && parent->subType() == Node::Collision) {
const NodeList& nl = parent->childNodes();
NodeList::ConstIterator it = nl.constBegin();
while (it != nl.constEnd()) {
if ((*it)->qmlModuleName() == relative->qmlModuleName()) {
/*
By returning here, we avoid printing
all the duplicate header warnings,
which are not really duplicates now,
because of the QML module name being
used as a namespace qualifier.
*/
dn = static_cast<const DocNode*>(*it);
return dn;
}
++it;
}
}
}
/*
Reporting all these duplicate section titles is probably
overkill. We should report the duplicate file and let
@ -1269,4 +1255,19 @@ void Tree::insertQmlType(const QString& key, QmlClassNode* n)
qmlTypeMap_.insert(key,n);
}
/*!
Split \a target on "::" and find the function node with that
path.
*/
const Node* Tree::resolveFunctionTarget(const QString& target, const Node* relative)
{
QString t = target;
t.chop(2);
QStringList path = t.split("::");
const FunctionNode* fn = findFunctionNode(path, relative, SearchBaseClasses);
if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
return fn;
return 0;
}
QT_END_NAMESPACE

View File

@ -86,10 +86,11 @@ class Tree
ClassNode* findClassNode(const QStringList& path, Node* start = 0) const;
NamespaceNode* findNamespaceNode(const QStringList& path) const;
FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone);
const Node* resolveFunctionTarget(const QString& target, const Node* relative);
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
Node* start,
const Node* start,
Node::Type type,
Node::SubType subtype,
bool acceptCollision = false) const;
@ -112,7 +113,7 @@ class Tree
Node* findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
bool acceptCollision = false);
bool acceptCollision = false) const;
InnerNode* findRelatesNode(const QStringList& path);
@ -121,8 +122,8 @@ class Tree
QString findTarget(const QString& target, const Node* node) const;
void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
void resolveTargets(InnerNode* root);
const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative);
const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const;
const Node* findUnambiguousTarget(const QString& target, QString& ref);
const DocNode* findDocNodeByTitle(const QString& title) const;
void addPropertyFunction(PropertyNode *property,
const QString &funcName,
@ -173,7 +174,7 @@ class Tree
ModuleNode* addToModule(const QString& name, Node* node);
QmlModuleNode* addToQmlModule(const QString& name, Node* node);
QmlClassNode* lookupQmlType(const QString& name) { return qmlTypeMap_.value(name); }
QmlClassNode* lookupQmlType(const QString& name) const { return qmlTypeMap_.value(name); }
void insertQmlType(const QString& key, QmlClassNode* n);
void addExampleNode(ExampleNode* n) { exampleNodeMap_.insert(n->title(), n); }
ExampleNodeMap& exampleNodeMap() { return exampleNodeMap_; }