summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@nokia.com>2010-07-22 11:27:43 (GMT)
committerToby Tomkins <toby.tomkins@nokia.com>2010-07-23 01:16:42 (GMT)
commit9a61d3f6c8a443791c1a379e4da80caf82737e9c (patch)
tree84eddc5df0163a25a4438a2ecabd749f65bfa1fd /tools
parentc6640f44cd782c249b2cb5ae39ad4604c6828094 (diff)
downloadQt-9a61d3f6c8a443791c1a379e4da80caf82737e9c.zip
Qt-9a61d3f6c8a443791c1a379e4da80caf82737e9c.tar.gz
Qt-9a61d3f6c8a443791c1a379e4da80caf82737e9c.tar.bz2
qdoc: Fixed reporting of read-only status for QML properties.
Task-number: QTBUG-11512 (cherry picked from commit d8908922f339892fee4275a433e2bf6da87ae055)
Diffstat (limited to 'tools')
-rw-r--r--tools/qdoc3/cppcodeparser.cpp32
-rw-r--r--tools/qdoc3/cppcodeparser.h1
-rw-r--r--tools/qdoc3/ditaxmlgenerator.cpp2
-rw-r--r--tools/qdoc3/htmlgenerator.cpp13
-rw-r--r--tools/qdoc3/node.cpp218
-rw-r--r--tools/qdoc3/node.h18
-rw-r--r--tools/qdoc3/test/qt-cpp-ignore.qdocconf4
-rw-r--r--tools/qdoc3/tokenizer.cpp6
-rw-r--r--tools/qdoc3/tokenizer.h2
-rw-r--r--tools/qdoc3/tree.cpp9
10 files changed, 263 insertions, 42 deletions
diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp
index d5108fd..a120e45 100644
--- a/tools/qdoc3/cppcodeparser.cpp
+++ b/tools/qdoc3/cppcodeparser.cpp
@@ -1120,6 +1120,17 @@ bool CppCodeParser::match(int target)
}
/*!
+ Skip to \a target. If \a target is found before the end
+ of input, return true. Otherwise return false.
+ */
+bool CppCodeParser::skipTo(int target)
+{
+ while ((tok != Tok_Eoi) && (tok != target))
+ readToken();
+ return (tok == target ? true : false);
+}
+
+/*!
If the current token is one of the keyword thingees that
are used in Qt, skip over it to the next token and return
true. Otherwise just return false without reading the
@@ -1362,7 +1373,9 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent,
if (!matchDataType(&returnType)) {
if (tokenizer->parsingFnOrMacro()
- && (match(Tok_Q_DECLARE_FLAGS) || match(Tok_Q_PROPERTY)))
+ && (match(Tok_Q_DECLARE_FLAGS) ||
+ match(Tok_Q_PROPERTY) ||
+ match(Tok_Q_PRIVATE_PROPERTY)))
returnType = CodeChunk(previousLexeme());
else {
return false;
@@ -1796,11 +1809,19 @@ bool CppCodeParser::matchTypedefDecl(InnerNode *parent)
bool CppCodeParser::matchProperty(InnerNode *parent)
{
- if (!match(Tok_Q_PROPERTY) &&
- !match(Tok_Q_OVERRIDE) &&
- !match(Tok_QDOC_PROPERTY))
+ int expected_tok = Tok_LeftParen;
+ if (match(Tok_Q_PRIVATE_PROPERTY)) {
+ expected_tok = Tok_Comma;
+ if (!skipTo(Tok_Comma))
+ return false;
+ }
+ else if (!match(Tok_Q_PROPERTY) &&
+ !match(Tok_Q_OVERRIDE) &&
+ !match(Tok_QDOC_PROPERTY)) {
return false;
- if (!match(Tok_LeftParen))
+ }
+
+ if (!match(expected_tok))
return false;
QString name;
@@ -1949,6 +1970,7 @@ bool CppCodeParser::matchDeclList(InnerNode *parent)
break;
case Tok_Q_OVERRIDE:
case Tok_Q_PROPERTY:
+ case Tok_Q_PRIVATE_PROPERTY:
case Tok_QDOC_PROPERTY:
matchProperty(parent);
break;
diff --git a/tools/qdoc3/cppcodeparser.h b/tools/qdoc3/cppcodeparser.h
index 3c53f72..55d9ddf 100644
--- a/tools/qdoc3/cppcodeparser.h
+++ b/tools/qdoc3/cppcodeparser.h
@@ -119,6 +119,7 @@ class CppCodeParser : public CodeParser
QString previousLexeme();
QString lexeme();
bool match(int target);
+ bool skipTo(int target);
bool matchCompat();
bool matchTemplateAngles(CodeChunk *type = 0);
bool matchTemplateHeader();
diff --git a/tools/qdoc3/ditaxmlgenerator.cpp b/tools/qdoc3/ditaxmlgenerator.cpp
index d7a9c9e..4789c67 100644
--- a/tools/qdoc3/ditaxmlgenerator.cpp
+++ b/tools/qdoc3/ditaxmlgenerator.cpp
@@ -4210,7 +4210,7 @@ void DitaXmlGenerator::generateDetailedQmlMember(const Node *node,
out() << "<td><p>";
//out() << "<tr><td>"; // old
out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
- if (!qpn->isWritable())
+ if (!qpn->isWritable(myTree))
out() << "<span class=\"qmlreadonly\">read-only</span>";
if (qpgn->isDefault())
out() << "<span class=\"qmldefault\">default</span>";
diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp
index 043731d..7e081db 100644
--- a/tools/qdoc3/htmlgenerator.cpp
+++ b/tools/qdoc3/htmlgenerator.cpp
@@ -4094,8 +4094,11 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
out() << "<td class=\"tblQmlPropNode\"><p>";
out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
- if (!qpn->isWritable())
+
+ if (!qpn->isWritable(myTree)) {
+ qDebug() << "QPN:" << qpn->name();
out() << "<span class=\"qmlreadonly\">read-only</span>";
+ }
if (qpgn->isDefault())
out() << "<span class=\"qmldefault\">default</span>";
generateQmlItem(qpn, relative, marker, false);
@@ -4111,10 +4114,10 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
out() << "<div class=\"qmlproto\">";
out() << "<table class=\"qmlname\">";
//out() << "<tr>";
- if (++numTableRows % 2 == 1)
- out() << "<tr class=\"odd\">";
- else
- out() << "<tr class=\"even\">";
+ if (++numTableRows % 2 == 1)
+ out() << "<tr class=\"odd\">";
+ else
+ out() << "<tr class=\"even\">";
out() << "<td class=\"tblQmlFuncNode\"><p>";
out() << "<a name=\"" + refForNode(qsn) + "\"></a>";
generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false);
diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp
index da62e29..28347c3 100644
--- a/tools/qdoc3/node.cpp
+++ b/tools/qdoc3/node.cpp
@@ -44,6 +44,8 @@
*/
#include "node.h"
+#include "tree.h"
+#include "codemarker.h"
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -171,6 +173,32 @@ QString Node::accessString() const
return "public";
}
+/*!
+ Extract a class name from the type \a string and return it.
+ */
+QString Node::extractClassName(const QString &string) const
+{
+ QString result;
+ for (int i=0; i<=string.size(); ++i) {
+ QChar ch;
+ if (i != string.size())
+ ch = string.at(i);
+
+ QChar lower = ch.toLower();
+ if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) ||
+ ch.digitValue() >= 0 ||
+ ch == QLatin1Char('_') ||
+ ch == QLatin1Char(':')) {
+ result += ch;
+ }
+ else if (!result.isEmpty()) {
+ if (result != QLatin1String("const"))
+ return result;
+ result.clear();
+ }
+ }
+ return result;
+}
/*!
Returns a string representing the access specifier.
@@ -426,6 +454,9 @@ void InnerNode::setOverload(const FunctionNode *func, bool overlode)
}
/*!
+ Mark all child nodes that have no documentation as having
+ private access and internal status. qdoc will then ignore
+ them for documentation purposes.
*/
void InnerNode::makeUndocumentedChildrenInternal()
{
@@ -831,6 +862,7 @@ NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
/*!
\class ClassNode
+ \brief This class represents a C++ class.
*/
/*!
@@ -850,8 +882,8 @@ void ClassNode::addBaseClass(Access access,
ClassNode *node,
const QString &dataTypeWithTemplateArgs)
{
- bas.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
- node->der.append(RelatedClass(access, this));
+ bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
+ node->derived.append(RelatedClass(access, this));
}
/*!
@@ -859,16 +891,16 @@ void ClassNode::addBaseClass(Access access,
void ClassNode::fixBaseClasses()
{
int i;
-
i = 0;
- while (i < bas.size()) {
- ClassNode *baseClass = bas.at(i).node;
- if (baseClass->access() == Node::Private) {
- bas.removeAt(i);
-
- const QList<RelatedClass> &basesBases = baseClass->baseClasses();
- for (int j = basesBases.size() - 1; j >= 0; --j)
- bas.insert(i, basesBases.at(j));
+ while (i < bases.size()) {
+ ClassNode* bc = bases.at(i).node;
+ if (bc->access() == Node::Private) {
+ RelatedClass rc = bases.at(i);
+ bases.removeAt(i);
+ ignoredBases.append(rc);
+ const QList<RelatedClass> &bb = bc->baseClasses();
+ for (int j = bb.size() - 1; j >= 0; --j)
+ bases.insert(i, bb.at(j));
}
else {
++i;
@@ -876,15 +908,13 @@ void ClassNode::fixBaseClasses()
}
i = 0;
- while (i < der.size()) {
- ClassNode *derivedClass = der.at(i).node;
- if (derivedClass->access() == Node::Private) {
- der.removeAt(i);
-
- const QList<RelatedClass> &dersDers =
- derivedClass->derivedClasses();
- for (int j = dersDers.size() - 1; j >= 0; --j)
- der.insert(i, dersDers.at(j));
+ while (i < derived.size()) {
+ ClassNode* dc = derived.at(i).node;
+ if (dc->access() == Node::Private) {
+ derived.removeAt(i);
+ const QList<RelatedClass> &dd = dc->derivedClasses();
+ for (int j = dd.size() - 1; j >= 0; --j)
+ derived.insert(i, dd.at(j));
}
else {
++i;
@@ -893,6 +923,16 @@ void ClassNode::fixBaseClasses()
}
/*!
+ Search the child list to find the property node with the
+ specified \a name.
+ */
+const PropertyNode* ClassNode::findPropertyNode(const QString& name) const
+{
+ const Node* n = findNode(name,Node::Property);
+ return (n ? static_cast<const PropertyNode*>(n) : 0);
+}
+
+/*!
\class FakeNode
*/
@@ -1567,6 +1607,144 @@ bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
return defaultValue;
}
}
+
+static QString valueType(const QString& n)
+{
+ if (n == "QPoint")
+ return "QDeclarativePointValueType";
+ if (n == "QPointF")
+ return "QDeclarativePointFValueType";
+ if (n == "QSize")
+ return "QDeclarativeSizeValueType";
+ if (n == "QSizeF")
+ return "QDeclarativeSizeFValueType";
+ if (n == "QRect")
+ return "QDeclarativeRectValueType";
+ if (n == "QRectF")
+ return "QDeclarativeRectFValueType";
+ if (n == "QVector2D")
+ return "QDeclarativeVector2DValueType";
+ if (n == "QVector3D")
+ return "QDeclarativeVector3DValueType";
+ if (n == "QVector4D")
+ return "QDeclarativeVector4DValueType";
+ if (n == "QQuaternion")
+ return "QDeclarativeQuaternionValueType";
+ if (n == "QMatrix4x4")
+ return "QDeclarativeMatrix4x4ValueType";
+ if (n == "QEasingCurve")
+ return "QDeclarativeEasingValueType";
+ if (n == "QFont")
+ return "QDeclarativeFontValueType";
+ return QString();
+}
+
+/*!
+ Returns true if a QML property or attached property is
+ read-only. The algorithm for figuring this out is long
+ amd tedious and almost certainly will break. It currently
+ doesn't work for qmlproperty bool PropertyChanges::explicit,
+ because the tokenized gets confused on "explicit" .
+ */
+bool QmlPropertyNode::isWritable(const Tree* tree) const
+{
+ Node* n = parent();
+ while (n && n->subType() != Node::QmlClass)
+ n = n->parent();
+ if (n) {
+ const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n);
+ const ClassNode* cn = qcn->classNode();
+ if (cn) {
+ QStringList dotSplit = name().split(QChar('.'));
+ const PropertyNode* pn = cn->findPropertyNode(dotSplit[0]);
+ if (pn) {
+ if (dotSplit.size() > 1) {
+ QStringList path(extractClassName(pn->qualifiedDataType()));
+ const Node* nn = tree->findNode(path,Class);
+ if (nn) {
+ const ClassNode* cn = static_cast<const ClassNode*>(nn);
+ pn = cn->findPropertyNode(dotSplit[1]);
+ if (pn) {
+ return pn->isWritable();
+ }
+ else {
+ const QList<RelatedClass>& bases = cn->baseClasses();
+ if (!bases.isEmpty()) {
+ for (int i=0; i<bases.size(); ++i) {
+ const ClassNode* cn = bases[i].node;
+ pn = cn->findPropertyNode(dotSplit[1]);
+ if (pn) {
+ return pn->isWritable();
+ }
+ }
+ }
+ const QList<RelatedClass>& ignoredBases = cn->ignoredBaseClasses();
+ if (!ignoredBases.isEmpty()) {
+ for (int i=0; i<ignoredBases.size(); ++i) {
+ const ClassNode* cn = ignoredBases[i].node;
+ pn = cn->findPropertyNode(dotSplit[1]);
+ if (pn) {
+ return pn->isWritable();
+ }
+ }
+ }
+ QString vt = valueType(cn->name());
+ if (!vt.isEmpty()) {
+ QStringList path(vt);
+ const Node* vtn = tree->findNode(path,Class);
+ if (vtn) {
+ const ClassNode* cn = static_cast<const ClassNode*>(vtn);
+ pn = cn->findPropertyNode(dotSplit[1]);
+ if (pn) {
+ return pn->isWritable();
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ return pn->isWritable();
+ }
+ }
+ else {
+ const QList<RelatedClass>& bases = cn->baseClasses();
+ if (!bases.isEmpty()) {
+ for (int i=0; i<bases.size(); ++i) {
+ const ClassNode* cn = bases[i].node;
+ pn = cn->findPropertyNode(dotSplit[0]);
+ if (pn) {
+ return pn->isWritable();
+ }
+ }
+ }
+ const QList<RelatedClass>& ignoredBases = cn->ignoredBaseClasses();
+ if (!ignoredBases.isEmpty()) {
+ for (int i=0; i<ignoredBases.size(); ++i) {
+ const ClassNode* cn = ignoredBases[i].node;
+ pn = cn->findPropertyNode(dotSplit[0]);
+ if (pn) {
+ return pn->isWritable();
+ }
+ }
+ }
+ if (isAttached()) {
+ QString classNameAttached = cn->name() + "Attached";
+ QStringList path(classNameAttached);
+ const Node* nn = tree->findNode(path,Class);
+ const ClassNode* acn = static_cast<const ClassNode*>(nn);
+ pn = acn->findPropertyNode(dotSplit[0]);
+ if (pn) {
+ return pn->isWritable();
+ }
+ }
+ }
+ }
+ }
+ location().warning(tr("Can't determine read-only status of QML property %1; writable assumed.").arg(name()));
+ return true;
+}
+
#endif
QT_END_NAMESPACE
diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h
index e9f2d74..3cc0f60 100644
--- a/tools/qdoc3/node.h
+++ b/tools/qdoc3/node.h
@@ -193,6 +193,7 @@ class Node
virtual QString fileBase() const;
QUuid guid() const;
QString ditaXmlHref();
+ QString extractClassName(const QString &string) const;
protected:
Node(Type type, InnerNode* parent, const QString& name);
@@ -326,6 +327,8 @@ struct RelatedClass
QString dataTypeWithTemplateArgs;
};
+class PropertyNode;
+
class ClassNode : public InnerNode
{
public:
@@ -337,8 +340,9 @@ class ClassNode : public InnerNode
const QString &dataTypeWithTemplateArgs = "");
void fixBaseClasses();
- const QList<RelatedClass> &baseClasses() const { return bas; }
- const QList<RelatedClass> &derivedClasses() const { return der; }
+ const QList<RelatedClass> &baseClasses() const { return bases; }
+ const QList<RelatedClass> &derivedClasses() const { return derived; }
+ const QList<RelatedClass> &ignoredBaseClasses() const { return ignoredBases; }
bool hideFromMainList() const { return hidden; }
void setHideFromMainList(bool value) { hidden = value; }
@@ -349,10 +353,12 @@ class ClassNode : public InnerNode
void setQmlElement(const QString& value) { qmlelement = value; }
virtual bool isAbstract() const { return abstract; }
virtual void setAbstract(bool b) { abstract = b; }
+ const PropertyNode* findPropertyNode(const QString& name) const;
private:
- QList<RelatedClass> bas;
- QList<RelatedClass> der;
+ QList<RelatedClass> bases;
+ QList<RelatedClass> derived;
+ QList<RelatedClass> ignoredBases;
bool hidden;
bool abstract;
QString sname;
@@ -436,6 +442,8 @@ class QmlPropGroupNode : public FakeNode
bool att;
};
+class Tree;
+
class QmlPropertyNode : public LeafNode
{
public:
@@ -454,7 +462,7 @@ class QmlPropertyNode : public LeafNode
QString qualifiedDataType() const { return dt; }
bool isStored() const { return fromTrool(sto,true); }
bool isDesignable() const { return fromTrool(des,false); }
- bool isWritable() const { return fromTrool(wri,true); }
+ bool isWritable(const Tree* tree) const;
bool isAttached() const { return att; }
virtual bool isQmlNode() const { return true; }
diff --git a/tools/qdoc3/test/qt-cpp-ignore.qdocconf b/tools/qdoc3/test/qt-cpp-ignore.qdocconf
index 8cc4fd9..4963b96 100644
--- a/tools/qdoc3/test/qt-cpp-ignore.qdocconf
+++ b/tools/qdoc3/test/qt-cpp-ignore.qdocconf
@@ -91,4 +91,6 @@ Cpp.ignoredirectives = Q_DECLARE_HANDLE \
K_DECLARE_PRIVATE \
PHONON_OBJECT \
PHONON_HEIR \
- Q_PRIVATE_PROPERTY
+ Q_PRIVATE_PROPERTY \
+ Q_DECLARE_PRIVATE_D \
+ Q_CLASSINFO
diff --git a/tools/qdoc3/tokenizer.cpp b/tools/qdoc3/tokenizer.cpp
index 7c10de6..05ad5ee 100644
--- a/tools/qdoc3/tokenizer.cpp
+++ b/tools/qdoc3/tokenizer.cpp
@@ -67,7 +67,11 @@ static const char *kwords[] = {
"private", "protected", "public", "short", "signals", "signed",
"slots", "static", "struct", "template", "typedef", "typename",
"union", "unsigned", "using", "virtual", "void", "volatile",
- "__int64", "Q_OBJECT", "Q_OVERRIDE", "Q_PROPERTY",
+ "__int64",
+ "Q_OBJECT",
+ "Q_OVERRIDE",
+ "Q_PROPERTY",
+ "Q_PRIVATE_PROPERTY",
"Q_DECLARE_SEQUENTIAL_ITERATOR",
"Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR",
"Q_DECLARE_ASSOCIATIVE_ITERATOR",
diff --git a/tools/qdoc3/tokenizer.h b/tools/qdoc3/tokenizer.h
index f55d2ef..bd35965 100644
--- a/tools/qdoc3/tokenizer.h
+++ b/tools/qdoc3/tokenizer.h
@@ -75,7 +75,7 @@ enum { Tok_Eoi, Tok_Ampersand, Tok_Aster, Tok_Caret, Tok_LeftParen,
Tok_static, Tok_struct, Tok_template, Tok_typedef,
Tok_typename, Tok_union, Tok_unsigned, Tok_using, Tok_virtual,
Tok_void, Tok_volatile, Tok_int64, Tok_Q_OBJECT, Tok_Q_OVERRIDE,
- Tok_Q_PROPERTY, Tok_Q_DECLARE_SEQUENTIAL_ITERATOR,
+ Tok_Q_PROPERTY, Tok_Q_PRIVATE_PROPERTY, Tok_Q_DECLARE_SEQUENTIAL_ITERATOR,
Tok_Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR,
Tok_Q_DECLARE_ASSOCIATIVE_ITERATOR,
Tok_Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR,
diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp
index d22a09a..56e3484 100644
--- a/tools/qdoc3/tree.cpp
+++ b/tools/qdoc3/tree.cpp
@@ -469,8 +469,9 @@ void Tree::resolveInheritance(NamespaceNode *rootNode)
for (int pass = 0; pass < 2; pass++) {
NodeList::ConstIterator c = rootNode->childNodes().begin();
while (c != rootNode->childNodes().end()) {
- if ((*c)->type() == Node::Class)
+ if ((*c)->type() == Node::Class) {
resolveInheritance(pass, (ClassNode *) *c);
+ }
else if ((*c)->type() == Node::Namespace) {
NamespaceNode *ns = static_cast<NamespaceNode*>(*c);
resolveInheritance(ns);
@@ -542,14 +543,16 @@ void Tree::resolveInheritance(int pass, ClassNode *classe)
while (b != bounds.end()) {
ClassNode *baseClass = (ClassNode*)findNode((*b).basePath,
Node::Class);
- if (!baseClass && (*b).parent)
+ if (!baseClass && (*b).parent) {
baseClass = (ClassNode*)findNode((*b).basePath,
Node::Class,
(*b).parent);
- if (baseClass)
+ }
+ if (baseClass) {
classe->addBaseClass((*b).access,
baseClass,
(*b).dataTypeWithTemplateArgs);
+ }
++b;
}
}