qdoc: qdoc's 'square bracket' parameters were evaluated too early

qdoc's link command (\l) allows an optional first argument enclosed in
square brackets. This argument is used for narrowing and focusing the
search for the link target. The argument should not be evaluated until
the generate phase, but it was being evaluated in the prepare
phase. This was also a problem when running qdoc in the single-exec
mode. This update prevents qdoc from evaluating the argument until it
is used in the generate phase.

Change-Id: I82785e97077053fb5f5c11f0592155675334aaeb
Task-number: QTBUG-42880
Reviewed-by: Martin Smith <martin.smith@digia.com>
bb10
Martin Smith 2014-11-25 15:18:49 +01:00
parent 9da1a12864
commit df6d2290e6
7 changed files with 72 additions and 28 deletions

View File

@ -379,15 +379,33 @@ void Atom::dump() const
the space character.
*/
LinkAtom::LinkAtom(const QString& p1, const QString& p2)
: Atom(p1), genus_(Node::DontCare), goal_(Node::NoType), domain_(0)
: Atom(p1),
resolved_(false),
genus_(Node::DontCare),
goal_(Node::NoType),
domain_(0),
squareBracketParams_(p2)
{
QStringList params = p2.toLower().split(QLatin1Char(' '));
foreach (const QString& p, params) {
// nada.
}
/*!
This function resolves the parameters that were enclosed in
square brackets. If the parameters have already been resolved,
it does nothing and returns immediately.
*/
void LinkAtom::resolveSquareBracketParams()
{
if (resolved_)
return;
QStringList params = squareBracketParams_.toLower().split(QLatin1Char(' '));
foreach (const QString& p, params) {
if (!domain_) {
domain_ = QDocDatabase::qdocDB()->findTree(p);
if (domain_)
continue;
}
if (domain_) {
continue;
}
}
if (goal_ == Node::NoType) {
goal_ = Node::goal(p);
if (goal_ != Node::NoType)
@ -401,9 +419,14 @@ LinkAtom::LinkAtom(const QString& p1, const QString& p2)
genus_ = Node::CPP;
continue;
}
error_ = p2;
if (p == "doc") {
genus_ = Node::DOC;
continue;
}
error_ = squareBracketParams_;
break;
}
resolved_ = true;
}
/*!
@ -411,10 +434,12 @@ LinkAtom::LinkAtom(const QString& p1, const QString& p2)
*/
LinkAtom::LinkAtom(const LinkAtom& t)
: Atom(Link, t.string()),
resolved_(t.resolved_),
genus_(t.genus_),
goal_(t.goal_),
domain_(t.domain_),
error_(t.error_)
error_(t.error_),
squareBracketParams_(t.squareBracketParams_)
{
// nothing
}
@ -426,10 +451,12 @@ LinkAtom::LinkAtom(const LinkAtom& t)
*/
LinkAtom::LinkAtom(Atom* previous, const LinkAtom& t)
: Atom(previous, Link, t.string()),
resolved_(t.resolved_),
genus_(t.genus_),
goal_(t.goal_),
domain_(t.domain_),
error_(t.error_)
error_(t.error_),
squareBracketParams_(t.squareBracketParams_)
{
previous->next_ = this;
}

View File

@ -194,11 +194,12 @@ public:
const QStringList& strings() const { return strs; }
virtual bool isLinkAtom() const { return false; }
virtual Node::Genus genus() const { return Node::DontCare; }
virtual bool specifiesDomain() const { return false; }
virtual Tree* domain() const { return 0; }
virtual Node::Type goal() const { return Node::NoType; }
virtual Node::Genus genus() { return Node::DontCare; }
virtual bool specifiesDomain() { return false; }
virtual Tree* domain() { return 0; }
virtual Node::Type goal() { return Node::NoType; }
virtual const QString& error() { return noError_; }
virtual void resolveSquareBracketParams() { }
protected:
static QString noError_;
@ -216,17 +217,20 @@ class LinkAtom : public Atom
virtual ~LinkAtom() { }
virtual bool isLinkAtom() const Q_DECL_OVERRIDE { return true; }
virtual Node::Genus genus() const Q_DECL_OVERRIDE { return genus_; }
virtual bool specifiesDomain() const Q_DECL_OVERRIDE { return (domain_ != 0); }
virtual Tree* domain() const Q_DECL_OVERRIDE { return domain_; }
virtual Node::Type goal() const Q_DECL_OVERRIDE { return goal_; }
virtual Node::Genus genus() Q_DECL_OVERRIDE { resolveSquareBracketParams(); return genus_; }
virtual bool specifiesDomain() Q_DECL_OVERRIDE { resolveSquareBracketParams(); return (domain_ != 0); }
virtual Tree* domain() Q_DECL_OVERRIDE { resolveSquareBracketParams(); return domain_; }
virtual Node::Type goal() Q_DECL_OVERRIDE { resolveSquareBracketParams(); return goal_; }
virtual const QString& error() Q_DECL_OVERRIDE { return error_; }
virtual void resolveSquareBracketParams() Q_DECL_OVERRIDE;
protected:
bool resolved_;
Node::Genus genus_;
Node::Type goal_;
Tree* domain_;
QString error_;
QString squareBracketParams_;
};
#define ATOM_FORMATTING_BOLD "bold"

View File

@ -732,7 +732,7 @@ Node *InnerNode::findChildNode(const QString& name, Node::Genus genus) const
if (!nodes.isEmpty()) {
for (int i=0; i<nodes.size(); ++i) {
Node* node = nodes.at(i);
if (genus == node->genus() || genus == Node::DontCare)
if (genus == node->genus())
return node;
}
}

View File

@ -107,7 +107,7 @@ public:
LastSubtype
};
enum Genus { DontCare, CPP, QML };
enum Genus { DontCare, CPP, QML, DOC };
enum Access { Public, Protected, Private };
@ -531,11 +531,13 @@ public:
virtual QString imageFileName() const { return QString(); }
virtual QString nameForLists() const Q_DECL_OVERRIDE { return title(); }
virtual void setImageFileName(const QString& ) { }
virtual bool isHeaderFile() const Q_DECL_OVERRIDE { return (subType() == Node::HeaderFile); }
virtual bool isExample() const Q_DECL_OVERRIDE { return (subType() == Node::Example); }
virtual bool isExampleFile() const Q_DECL_OVERRIDE { return (parent() && parent()->isExample()); }
virtual bool isExternalPage() const Q_DECL_OVERRIDE { return nodeSubtype_ == ExternalPage; }
virtual bool isDocNode() const Q_DECL_OVERRIDE { return true; }
virtual Node::Genus genus() const Q_DECL_OVERRIDE { return Node::DOC; }
protected:
SubType nodeSubtype_;

View File

@ -1606,10 +1606,11 @@ void QDocDatabase::mergeCollections(CollectionNode* cn)
\a ref. If the returned node pointer is null, \a ref is not
valid.
*/
const Node* QDocDatabase::findNodeForAtom(const Atom* atom, const Node* relative, QString& ref)
const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, QString& ref)
{
const Node* node = 0;
Atom* atom = const_cast<Atom*>(a);
QStringList targetPath = atom->string().split("#");
QString first = targetPath.first().trimmed();

View File

@ -73,6 +73,9 @@ class QDocForest
Tree* nextTree();
Tree* primaryTree() { return primaryTree_; }
Tree* findTree(const QString& t) { return forest_.value(t); }
QStringList keys() {
return forest_.keys();
}
NamespaceNode* primaryTreeRoot() { return (primaryTree_ ? primaryTree_->root() : 0); }
bool isEmpty() { return searchOrder().isEmpty(); }
bool done() { return (currentIndex_ >= searchOrder().size()); }
@ -401,6 +404,9 @@ class QDocDatabase
}
TargetList* getTargetList(const QString& t) { return primaryTree()->getTargetList(t); }
QStringList getTargetListKeys() { return primaryTree()->getTargetListKeys(); }
QStringList keys() {
return forest_.keys();
}
private:
friend class QDocIndexFiles;

View File

@ -219,7 +219,8 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
int findFlags,
Node::Genus genus) const
{
if (path.size() == 3 && !path[0].isEmpty() && (genus != Node::CPP)) {
if (path.size() == 3 && !path[0].isEmpty() &&
((genus == Node::QML) || (genus == Node::DontCare))) {
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (!qcn) {
QStringList p(path[1]);
@ -691,7 +692,7 @@ const Node* Tree::findNodeForTarget(const QStringList& path,
QString p;
if (path.size() > 1)
p = path.join(QString("::"));
else {
else if ((genus == Node::DontCare) || (genus == Node::DOC)) {
p = path.at(0);
node = findDocNodeByTitle(p);
if (node) {
@ -728,7 +729,8 @@ const Node* Tree::findNodeForTarget(const QStringList& path,
type node.
*/
int path_idx = 0;
if ((genus != Node::CPP) && (path.size() >= 2) && !path[0].isEmpty()) {
if (((genus == Node::QML) || (genus == Node::DontCare)) &&
(path.size() >= 2) && !path[0].isEmpty()) {
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (qcn) {
current = qcn;
@ -737,8 +739,7 @@ const Node* Tree::findNodeForTarget(const QStringList& path,
ref = getRef(target, current);
if (!ref.isEmpty())
return current;
else if (genus == Node::QML)
return 0;
return 0;
}
else
return current;
@ -824,7 +825,8 @@ const Node* Tree::matchPathAndTarget(const QStringList& path,
return t;
}
}
if ((genus != Node::QML) && node->isClass() && (flags & SearchBaseClasses)) {
if (((genus == Node::CPP) || (genus == Node::DontCare)) &&
node->isClass() && (flags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const Node* bc, baseClasses) {
t = matchPathAndTarget(path, idx, target, bc, flags, genus, ref);
@ -872,7 +874,8 @@ const Node* Tree::findNode(const QStringList& path,
If the answer is yes, the reference identifies a QML
type node.
*/
if ((genus != Node::CPP) && (path.size() >= 2) && !path[0].isEmpty()) {
if (((genus == Node::QML) || (genus == Node::DontCare)) &&
(path.size() >= 2) && !path[0].isEmpty()) {
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (qcn) {
node = qcn;
@ -890,7 +893,8 @@ const Node* Tree::findNode(const QStringList& path,
if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) {
next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
}
if (!next && (genus != Node::QML) && node->isClass() && (findFlags & SearchBaseClasses)) {
if (!next && ((genus == Node::CPP) || (genus == Node::DontCare)) &&
node->isClass() && (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), genus);