summaryrefslogtreecommitdiff
path: root/src/qdoc/clangcodeparser.cpp
diff options
context:
space:
mode:
authorTopi Reinio <topi.reinio@qt.io>2023-02-10 18:53:40 +0000
committerTopi Reinio <topi.reinio@qt.io>2023-02-14 12:31:02 +0000
commit6e68db8c10001f58fcc1d93e2e7291ac3ac7d42d (patch)
tree97e1afadd361873c3d80f8932d58fa804cbd289c /src/qdoc/clangcodeparser.cpp
parent501a5fbac4b82cf7746aa49aa62bc0bcc331ef2f (diff)
downloadqttools-6e68db8c10001f58fcc1d93e2e7291ac3ac7d42d.tar.gz
qdoc: Improve Q_PROPERTY parsing for the property type
QDoc had a naive strategy for parsing Q_PROPERTY() macro arguments for resolving the type and name; when the argument string is separated by spaces, the first item was assumed to be the type, and the second item the name. This failed for following valid declarations: Q_PROPERTY(QMap<QString, QString> map ...) // type contains a space Q_PROPERTY(Type * handle ...) // '*' interpreted as the name Fix this by locating the first property attribute and then splitting the input at that boundary. This allows QDoc to extract the property type and name without making any assumptions about their syntax. Remove old workarounds as unnecessary and implement safeguards for invalid input. Also handle the MEMBER attribute correctly as it implies the property is writable, whether the WRITE accessor is set or not. Pick-to: 6.2 6.4 6.5 Fixes: QTBUG-111093 Change-Id: Ic1bf071a7b003a1cd0cb9a212dabdb7ea00ebfbe Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Luca Di Sera <luca.disera@qt.io>
Diffstat (limited to 'src/qdoc/clangcodeparser.cpp')
-rw-r--r--src/qdoc/clangcodeparser.cpp48
1 files changed, 31 insertions, 17 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index 30eb32929..c28629941 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -1053,32 +1053,44 @@ bool ClangVisitor::parseProperty(const QString &spelling, const Location &loc)
QString signature = spelling.mid(lpIdx + 1, rpIdx - lpIdx - 1);
signature = signature.simplified();
-
- QString type;
- QString name;
QStringList parts = signature.split(QChar(' '), Qt::SkipEmptyParts);
- if (parts.size() < 2)
- return false;
- if (parts.first() == QLatin1String("enum"))
- parts.removeFirst(); // QTBUG-80027
- type = parts.takeFirst();
- if (type == QLatin1String("const") && !parts.empty())
- type += " " + parts.takeFirst();
+ static const QStringList attrs =
+ QStringList() << "READ" << "MEMBER" << "WRITE"
+ << "NOTIFY" << "CONSTANT" << "FINAL"
+ << "REQUIRED" << "BINDABLE" << "DESIGNABLE"
+ << "RESET" << "REVISION" << "SCRIPTABLE"
+ << "STORED" << "USER";
+
+ // Find the location of the first attribute. All preceding parts
+ // represent the property type + name.
+ auto it = std::find_if(parts.cbegin(), parts.cend(),
+ [](const QString &attr) -> bool {
+ return attrs.contains(attr);
+ });
- if (!parts.empty())
- name = parts.takeFirst();
- else
+ if (it == parts.cend() || std::distance(parts.cbegin(), it) < 2)
return false;
- if (name.front() == QChar('*')) {
- type.append(QChar('*'));
- name.remove(0, 1);
+ QStringList typeParts;
+ std::copy(parts.cbegin(), it, std::back_inserter(typeParts));
+ parts.erase(parts.cbegin(), it);
+ QString name = typeParts.takeLast();
+
+ // Move the pointer operator(s) from name to type
+ while (!name.isEmpty() && name.front() == QChar('*')) {
+ typeParts.last().push_back(name.front());
+ name.removeFirst();
}
+
+ // Need at least READ or MEMBER + getter/member name
+ if (parts.size() < 2 || name.isEmpty())
+ return false;
+
auto *property = new PropertyNode(parent_, name);
property->setAccess(Access::Public);
property->setLocation(loc);
- property->setDataType(type);
+ property->setDataType(typeParts.join(QChar(' ')));
int i = 0;
while (i < parts.size()) {
@@ -1096,6 +1108,8 @@ bool ClangVisitor::parseProperty(const QString &spelling, const Location &loc)
} else if (key == "WRITE") {
qdb_->addPropertyFunction(property, value, PropertyNode::FunctionRole::Setter);
property->setWritable(true);
+ } else if (key == "MEMBER") {
+ property->setWritable(true);
} else if (key == "STORED") {
property->setStored(value.toLower() == "true");
} else if (key == "BINDABLE") {