aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSami Shalayel <sami.shalayel@qt.io>2023-05-04 10:25:17 +0200
committerSami Shalayel <sami.shalayel@qt.io>2023-05-23 10:58:22 +0200
commitaf6234be944c3057a54589d3c2bc3bd19bf290cd (patch)
tree76b3c9b73fe81cd2f6c29befd73f52df2256941c /src
parent435488bdeabe7449d00b0efb968ede3f6c634f5f (diff)
QmlDom: implement the FieldMemberExpression
Implement expressions like "someId.propertyX" in QmlDom as a BinaryExpression. Fix the BinaryExpression to have an enum as operator, but only implement it for FieldMemberExpression and ArrayMemberExpressions (as other operations are ignored by qmlls for now). This is needed for qmlls to be able to find usages of QML object ids and properties when using 'someId.propertyX' or 'someIf["propertyX"]' in JS code. Also, replace one assert in qqmllsutils with a warning, as it crashes unrelated tests. The checked condition is indeed not critical, in the worst case some DomItem might not be able to be looked up from their text position. See test in following commit. Fixes: QTBUG-113381 Task-number: QTBUG-92876 Task-number: QTBUG-111415 Change-Id: I85c0703ec0b6e6f90962c4b3172ff084c3c2d606 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qmldom/qqmldomastcreator.cpp64
-rw-r--r--src/qmldom/qqmldomastcreator_p.h6
-rw-r--r--src/qmldom/qqmldomscriptelements_p.h11
-rw-r--r--src/qmlls/qqmllsutils.cpp9
4 files changed, 84 insertions, 6 deletions
diff --git a/src/qmldom/qqmldomastcreator.cpp b/src/qmldom/qqmldomastcreator.cpp
index c9152009ef..4658b41819 100644
--- a/src/qmldom/qqmldomastcreator.cpp
+++ b/src/qmldom/qqmldomastcreator.cpp
@@ -1098,7 +1098,6 @@ void QQmlDomAstCreator::endVisit(AST::BinaryExpression *exp)
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
- current->setOp(exp->op);
pushScriptElement(current);
}
@@ -1369,6 +1368,69 @@ void QQmlDomAstCreator::endVisit(AST::ReturnStatement *returnStatement)
pushScriptElement(current);
}
+bool QQmlDomAstCreator::visit(AST::FieldMemberExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::FieldMemberExpression *expression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
+ current->setOp(ScriptElements::BinaryExpression::FieldMemberAccess);
+
+ if (expression->base) {
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ current->setLeft(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (!expression->name.empty()) {
+ auto scriptIdentifier =
+ std::make_shared<ScriptElements::IdentifierExpression>(expression->identifierToken);
+ scriptIdentifier->setName(expression->name);
+ current->setRight(ScriptElementVariant::fromElement(scriptIdentifier));
+ }
+
+ pushScriptElement(current);
+}
+
+bool QQmlDomAstCreator::visit(AST::ArrayMemberExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::ArrayMemberExpression *expression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeScriptElement<ScriptElements::BinaryExpression>(expression);
+ current->setOp(ScriptElements::BinaryExpression::ArrayMemberAccess);
+
+ if (expression->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ current->setRight(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ if (expression->base) {
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ current->setLeft(currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
bool QQmlDomAstCreator::visit(AST::CallExpression *)
{
if (!m_enableScriptExpressions)
diff --git a/src/qmldom/qqmldomastcreator_p.h b/src/qmldom/qqmldomastcreator_p.h
index c38fef4602..3f14dca9ea 100644
--- a/src/qmldom/qqmldomastcreator_p.h
+++ b/src/qmldom/qqmldomastcreator_p.h
@@ -337,6 +337,12 @@ public:
bool visit(AST::IfStatement *) override;
void endVisit(AST::IfStatement *) override;
+ bool visit(AST::FieldMemberExpression *) override;
+ void endVisit(AST::FieldMemberExpression *) override;
+
+ bool visit(AST::ArrayMemberExpression *) override;
+ void endVisit(AST::ArrayMemberExpression *) override;
+
bool visit(AST::CallExpression *) override;
void endVisit(AST::CallExpression *) override;
diff --git a/src/qmldom/qqmldomscriptelements_p.h b/src/qmldom/qqmldomscriptelements_p.h
index 302a692eb5..6f7ff73d0a 100644
--- a/src/qmldom/qqmldomscriptelements_p.h
+++ b/src/qmldom/qqmldomscriptelements_p.h
@@ -19,6 +19,7 @@
#include "qqmldomattachedinfo_p.h"
#include "qqmldompath_p.h"
#include <algorithm>
+#include <limits>
#include <type_traits>
#include <utility>
#include <variant>
@@ -295,6 +296,12 @@ class BinaryExpression : public ScriptElementBase<DomType::ScriptBinaryExpressio
public:
using BaseT::BaseT;
+ enum Operator : char {
+ FieldMemberAccess,
+ ArrayMemberAccess,
+ TO_BE_IMPLEMENTED = std::numeric_limits<char>::max(), // not required by qmlls
+ };
+
// minimal required overload for this to be wrapped as DomItem:
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
void updatePathFromOwner(Path p) override;
@@ -305,12 +312,12 @@ public:
ScriptElementVariant right() const { return m_right; }
void setRight(const ScriptElementVariant &newRight) { m_right = newRight; }
int op() const { return m_operator; }
- void setOp(int op) { m_operator = op; }
+ void setOp(Operator op) { m_operator = op; }
private:
ScriptElementVariant m_left;
ScriptElementVariant m_right;
- int m_operator; // TODO: Do an enum out of it?
+ Operator m_operator = TO_BE_IMPLEMENTED;
};
class VariableDeclarationEntry : public ScriptElementBase<DomType::ScriptVariableDeclarationEntry>
diff --git a/src/qmlls/qqmllsutils.cpp b/src/qmlls/qqmllsutils.cpp
index 36a98ff329..7251e5aeac 100644
--- a/src/qmlls/qqmllsutils.cpp
+++ b/src/qmlls/qqmllsutils.cpp
@@ -184,9 +184,12 @@ QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(DomItem file,
if (containsTarget(subLoc->info().fullRegion)) {
QQmlLSUtilsItemLocation subItem;
subItem.domItem = iLoc.domItem.path(it.key());
- Q_ASSERT_X(subItem.domItem, "QQmlLSUtils::itemsFromTextLocation",
- "A DomItem child is missing or the FileLocationsTree structure does not "
- "follow the DomItem Structure.");
+ if (!subItem.domItem) {
+ qCDebug(QQmlLSUtilsLog)
+ << "A DomItem child is missing or the FileLocationsTree structure does "
+ "not follow the DomItem Structure.";
+ continue;
+ }
subItem.fileLocation = subLoc;
toDo.append(subItem);
inParentButOutsideChildren = false;