aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier De Cannière <olivier.decanniere@qt.io>2024-04-02 11:23:56 +0200
committerOlivier De Cannière <olivier.decanniere@qt.io>2024-04-17 12:27:36 +0200
commit779d60cc432c4fc1b71c41db0f73eec309e5ee14 (patch)
treec4c2955caaa9b869ce46aab7efff4b2ebd4e4d3b
parentf0d265e3f52e25b1081e56b5ce811376be6f6c51 (diff)
QQmlJS: Store method's source location and expose it in QQmlSA
This is useful for tooling like Axivion and can help with better error messages. Change-Id: Ic63afd2eeb4ee3627d05303c2518fa90282fb7ab Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp3
-rw-r--r--src/qmlcompiler/qqmljsmetatypes_p.h5
-rw-r--r--src/qmlcompiler/qqmlsa.cpp14
-rw-r--r--src/qmlcompiler/qqmlsa.h1
-rw-r--r--src/qmlcompiler/qqmlsa_p.h1
-rw-r--r--tests/auto/qml/qqmljsscope/data/methodAndSignalSourceLocation.qml16
-rw-r--r--tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp30
7 files changed, 70 insertions, 0 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index ff942886de..25d5944be2 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -1590,6 +1590,8 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
QQmlJSMetaMethod method;
method.setMethodType(QQmlJSMetaMethodType::Signal);
method.setMethodName(publicMember->name.toString());
+ method.setSourceLocation(combine(publicMember->firstSourceLocation(),
+ publicMember->lastSourceLocation()));
while (param) {
method.addParameter(
QQmlJSMetaParameter(
@@ -1725,6 +1727,7 @@ void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExp
if (!name.isEmpty()) {
QQmlJSMetaMethod method(name);
method.setMethodType(QQmlJSMetaMethodType::Method);
+ method.setSourceLocation(combine(fexpr->firstSourceLocation(), fexpr->lastSourceLocation()));
if (!m_pendingMethodAnnotations.isEmpty()) {
method.setAnnotations(m_pendingMethodAnnotations);
diff --git a/src/qmlcompiler/qqmljsmetatypes_p.h b/src/qmlcompiler/qqmljsmetatypes_p.h
index 547a814a8d..0ea7020a2d 100644
--- a/src/qmlcompiler/qqmljsmetatypes_p.h
+++ b/src/qmlcompiler/qqmljsmetatypes_p.h
@@ -221,6 +221,9 @@ public:
QString methodName() const { return m_name; }
void setMethodName(const QString &name) { m_name = name; }
+ QQmlJS::SourceLocation sourceLocation() const { return m_sourceLocation; }
+ void setSourceLocation(QQmlJS::SourceLocation location) { m_sourceLocation = location; }
+
QQmlJSMetaReturnType returnValue() const { return m_returnType; }
void setReturnValue(const QQmlJSMetaReturnType returnValue) { m_returnType = returnValue; }
QString returnTypeName() const { return m_returnType.typeName(); }
@@ -338,6 +341,8 @@ public:
private:
QString m_name;
+ QQmlJS::SourceLocation m_sourceLocation;
+
QQmlJSMetaReturnType m_returnType;
QList<QQmlJSMetaParameter> m_parameters;
QList<QQmlJSAnnotation> m_annotations;
diff --git a/src/qmlcompiler/qqmlsa.cpp b/src/qmlcompiler/qqmlsa.cpp
index 00bb279723..d2d0e6a74e 100644
--- a/src/qmlcompiler/qqmlsa.cpp
+++ b/src/qmlcompiler/qqmlsa.cpp
@@ -314,6 +314,11 @@ QString MethodPrivate::methodName() const
return m_method.methodName();
}
+QQmlSA::SourceLocation MethodPrivate::sourceLocation() const
+{
+ return QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(m_method.sourceLocation());
+}
+
MethodType MethodPrivate::methodType() const
{
return m_method.methodType();
@@ -376,6 +381,15 @@ MethodType Method::methodType() const
return d->methodType();
}
+/*!
+ Returns the location in the QML code where this method is defined.
+ */
+QQmlSA::SourceLocation Method::sourceLocation() const
+{
+ Q_D(const Method);
+ return d->sourceLocation();
+}
+
bool Method::operatorEqualsImpl(const Method &lhs, const Method &rhs)
{
return lhs.d_func()->m_method == rhs.d_func()->m_method;
diff --git a/src/qmlcompiler/qqmlsa.h b/src/qmlcompiler/qqmlsa.h
index 42878031ba..e63f9ea5ab 100644
--- a/src/qmlcompiler/qqmlsa.h
+++ b/src/qmlcompiler/qqmlsa.h
@@ -138,6 +138,7 @@ public:
~Method();
QString methodName() const;
+ QQmlSA::SourceLocation sourceLocation() const;
MethodType methodType() const;
friend bool operator==(const Method &lhs, const Method &rhs)
diff --git a/src/qmlcompiler/qqmlsa_p.h b/src/qmlcompiler/qqmlsa_p.h
index 2388279551..9c9f557e22 100644
--- a/src/qmlcompiler/qqmlsa_p.h
+++ b/src/qmlcompiler/qqmlsa_p.h
@@ -121,6 +121,7 @@ public:
MethodPrivate(Method *, const MethodPrivate &);
QString methodName() const;
+ QQmlSA::SourceLocation sourceLocation() const;
MethodType methodType() const;
static QQmlSA::Method createMethod(const QQmlJSMetaMethod &);
diff --git a/tests/auto/qml/qqmljsscope/data/methodAndSignalSourceLocation.qml b/tests/auto/qml/qqmljsscope/data/methodAndSignalSourceLocation.qml
new file mode 100644
index 0000000000..52841e323c
--- /dev/null
+++ b/tests/auto/qml/qqmljsscope/data/methodAndSignalSourceLocation.qml
@@ -0,0 +1,16 @@
+import QtQml
+
+QtObject {
+ function f1() { }
+ function f2(a) { }
+ function f3(a: int) { }
+ function f4(a, b) { }
+ function f5(a, b): void { }
+ function f6(a, b, c): void {
+ // Nothing
+ }
+
+ signal s1()
+ signal s2(a: int)
+ signal s3(a: int, b: string)
+}
diff --git a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
index 60c0da78de..db81c77206 100644
--- a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
+++ b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
@@ -114,6 +114,7 @@ private Q_SLOTS:
void attachedTypeResolution();
void builtinTypeResolution_data();
void builtinTypeResolution();
+ void methodAndSignalSourceLocation();
public:
tst_qqmljsscope()
@@ -929,5 +930,34 @@ void tst_qqmljsscope::builtinTypeResolution()
QCOMPARE(element.isNull(), !valid);
}
+void tst_qqmljsscope::methodAndSignalSourceLocation()
+{
+ QmlIR::Document document(false);
+ auto jsscope = run(u"methodAndSignalSourceLocation.qml"_s, false);
+
+ std::array<std::array<int, 9>, 2> offsetsByLineEnding = {
+ std::array{ 29, 51, 74, 102, 128, 160, 219, 235, 257 }, // 1 char line endings
+ std::array{ 32, 55, 79, 108, 135, 168, 231, 248, 271 } // 2 char line endinds
+ };
+
+ // Try to detect the size of line endings as they lead to different source locations
+ auto offset1 = jsscope->methods("f1")[0].sourceLocation().offset;
+ QVERIFY(offset1 == 29 || offset1 == 32);
+ bool oneCharEndings = offset1 == 29;
+ std::array<int, 9> &offsets = oneCharEndings ? offsetsByLineEnding[0] : offsetsByLineEnding[1];
+
+ using namespace QQmlJS;
+ QCOMPARE(jsscope->methods("f1")[0].sourceLocation(), SourceLocation(offsets[0], 17, 4, 5));
+ QCOMPARE(jsscope->methods("f2")[0].sourceLocation(), SourceLocation(offsets[1], 18, 5, 5));
+ QCOMPARE(jsscope->methods("f3")[0].sourceLocation(), SourceLocation(offsets[2], 23, 6, 5));
+ QCOMPARE(jsscope->methods("f4")[0].sourceLocation(), SourceLocation(offsets[3], 21, 7, 5));
+ QCOMPARE(jsscope->methods("f5")[0].sourceLocation(), SourceLocation(offsets[4], 27, 8, 5));
+ QCOMPARE(jsscope->methods("f6")[0].sourceLocation(), SourceLocation(offsets[5], oneCharEndings ? 53 : 55, 9, 5));
+
+ QCOMPARE(jsscope->methods("s1")[0].sourceLocation(), SourceLocation(offsets[6], 11, 13, 5));
+ QCOMPARE(jsscope->methods("s2")[0].sourceLocation(), SourceLocation(offsets[7], 17, 14, 5));
+ QCOMPARE(jsscope->methods("s3")[0].sourceLocation(), SourceLocation(offsets[8], 28, 15, 5));
+}
+
QTEST_MAIN(tst_qqmljsscope)
#include "tst_qqmljsscope.moc"