aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-11-11 18:18:04 +0100
committerUlf Hermann <ulf.hermann@qt.io>2019-11-18 10:39:23 +0100
commit6fb335ebcec9c5efc6a2d7786e7bbba23c583d48 (patch)
tree8cc161f7423757e6820d9db40a943464f98fc3aa /tools
parent61d7713ead80a6f5b972778d2e47843af756039e (diff)
qmllint: Cleanup
qmllint needed to be refactored before we can add any new functionality: * Fix all the (C++) linter warnings * Remove pointless namespaces * Merge ScopeTree and FakeMetaObject into one class * Remove the "Fake" from class and variable names * Remove dead code * Add "We mean it" warnings everywhere * Unify #include style This also "accidentally" fixes the automatic matching of signal handlers in Connections elements to signals in their parent scopes. Change-Id: Idf8daae34dfd6c0ee00da28b017f921da3eba25c Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qmllint/componentversion.cpp63
-rw-r--r--tools/qmllint/componentversion.h43
-rw-r--r--tools/qmllint/fakemetaobject.cpp594
-rw-r--r--tools/qmllint/fakemetaobject.h235
-rw-r--r--tools/qmllint/findunqualified.cpp343
-rw-r--r--tools/qmllint/findunqualified.h63
-rw-r--r--tools/qmllint/main.cpp66
-rw-r--r--tools/qmllint/metatypes.h146
-rw-r--r--tools/qmllint/qcoloroutput.cpp157
-rw-r--r--tools/qmllint/qcoloroutput.h (renamed from tools/qmllint/qcoloroutput_p.h)23
-rw-r--r--tools/qmllint/qmljstypedescriptionreader.h103
-rw-r--r--tools/qmllint/qmllint.pro13
-rw-r--r--tools/qmllint/scopetree.cpp229
-rw-r--r--tools/qmllint/scopetree.h170
-rw-r--r--tools/qmllint/typedescriptionreader.cpp (renamed from tools/qmllint/qmljstypedescriptionreader.cpp)359
-rw-r--r--tools/qmllint/typedescriptionreader.h105
16 files changed, 1053 insertions, 1659 deletions
diff --git a/tools/qmllint/componentversion.cpp b/tools/qmllint/componentversion.cpp
index 3dc4ac37d0..e5047b8302 100644
--- a/tools/qmllint/componentversion.cpp
+++ b/tools/qmllint/componentversion.cpp
@@ -27,67 +27,24 @@
****************************************************************************/
#include "componentversion.h"
-
-#include <QString>
-#include <QCryptographicHash>
-
-#include <limits>
-
-using namespace LanguageUtils;
-
-const int ComponentVersion::NoVersion = -1;
-const int ComponentVersion::MaxVersion = std::numeric_limits<int>::max();
-
-ComponentVersion::ComponentVersion()
- : _major(NoVersion), _minor(NoVersion)
-{
-}
-
-ComponentVersion::ComponentVersion(int major, int minor)
- : _major(major), _minor(minor)
-{
-}
+#include <QtCore/qstring.h>
ComponentVersion::ComponentVersion(const QString &versionString)
- : _major(NoVersion), _minor(NoVersion)
{
- int dotIdx = versionString.indexOf(QLatin1Char('.'));
+ const int dotIdx = versionString.indexOf(QLatin1Char('.'));
if (dotIdx == -1)
return;
bool ok = false;
- int maybeMajor = versionString.leftRef(dotIdx).toInt(&ok);
+ const int maybeMajor = versionString.leftRef(dotIdx).toInt(&ok);
if (!ok)
return;
- int maybeMinor = versionString.midRef(dotIdx + 1).toInt(&ok);
+ const int maybeMinor = versionString.midRef(dotIdx + 1).toInt(&ok);
if (!ok)
return;
- _major = maybeMajor;
- _minor = maybeMinor;
-}
-
-ComponentVersion::~ComponentVersion()
-{
+ m_major = maybeMajor;
+ m_minor = maybeMinor;
}
-bool ComponentVersion::isValid() const
-{
- return _major >= 0 && _minor >= 0;
-}
-
-QString ComponentVersion::toString() const
-{
- return QString::fromLatin1("%1.%2").arg(QString::number(_major),
- QString::number(_minor));
-}
-
-void ComponentVersion::addToHash(QCryptographicHash &hash) const
-{
- hash.addData(reinterpret_cast<const char *>(&_major), sizeof(_major));
- hash.addData(reinterpret_cast<const char *>(&_minor), sizeof(_minor));
-}
-
-namespace LanguageUtils {
-
bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
return lhs.majorVersion() < rhs.majorVersion()
@@ -97,7 +54,8 @@ bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs)
bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
return lhs.majorVersion() < rhs.majorVersion()
- || (lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() <= rhs.minorVersion());
+ || (lhs.majorVersion() == rhs.majorVersion()
+ && lhs.minorVersion() <= rhs.minorVersion());
}
bool operator>(const ComponentVersion &lhs, const ComponentVersion &rhs)
@@ -112,12 +70,11 @@ bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs)
bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
- return lhs.majorVersion() == rhs.majorVersion() && lhs.minorVersion() == rhs.minorVersion();
+ return lhs.majorVersion() == rhs.majorVersion()
+ && lhs.minorVersion() == rhs.minorVersion();
}
bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs)
{
return !(lhs == rhs);
}
-
-}
diff --git a/tools/qmllint/componentversion.h b/tools/qmllint/componentversion.h
index 9d079f1d30..9c4604b9a3 100644
--- a/tools/qmllint/componentversion.h
+++ b/tools/qmllint/componentversion.h
@@ -29,36 +29,35 @@
#ifndef COMPONENTVERSION_H
#define COMPONENTVERSION_H
-#include <qglobal.h>
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
-QT_BEGIN_NAMESPACE
-class QCryptographicHash;
-QT_END_NAMESPACE
-
-namespace LanguageUtils {
+#include <QtCore/qglobal.h>
class ComponentVersion
{
- int _major;
- int _minor;
-
public:
- static const int NoVersion;
- static const int MaxVersion;
+ static const int NoVersion = -1;
- ComponentVersion();
- ComponentVersion(int major, int minor);
+ ComponentVersion() = default;
+ ComponentVersion(int major, int minor) : m_major(major), m_minor(minor) {}
explicit ComponentVersion(const QString &versionString);
- ~ComponentVersion();
- int majorVersion() const
- { return _major; }
- int minorVersion() const
- { return _minor; }
+ int majorVersion() const { return m_major; }
+ int minorVersion() const { return m_minor; }
- bool isValid() const;
- QString toString() const;
- void addToHash(QCryptographicHash &hash) const;
+ bool isValid() const { return m_major >= 0 && m_minor >= 0; }
+
+private:
+ int m_major = NoVersion;
+ int m_minor = NoVersion;
};
bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs);
@@ -68,6 +67,4 @@ bool operator>=(const ComponentVersion &lhs, const ComponentVersion &rhs);
bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs);
bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs);
-} // namespace LanguageUtils
-
#endif // COMPONENTVERSION_H
diff --git a/tools/qmllint/fakemetaobject.cpp b/tools/qmllint/fakemetaobject.cpp
deleted file mode 100644
index 8319ae6713..0000000000
--- a/tools/qmllint/fakemetaobject.cpp
+++ /dev/null
@@ -1,594 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "fakemetaobject.h"
-#include <QCryptographicHash>
-
-using namespace LanguageUtils;
-
-FakeMetaEnum::FakeMetaEnum()
-{}
-
-FakeMetaEnum::FakeMetaEnum(const QString &name)
- : m_name(name)
-{}
-
-bool FakeMetaEnum::isValid() const
-{ return !m_name.isEmpty(); }
-
-QString FakeMetaEnum::name() const
-{ return m_name; }
-
-void FakeMetaEnum::setName(const QString &name)
-{ m_name = name; }
-
-void FakeMetaEnum::addKey(const QString &key)
-{ m_keys.append(key); }
-
-QString FakeMetaEnum::key(int index) const
-{ return m_keys.at(index); }
-
-int FakeMetaEnum::keyCount() const
-{ return m_keys.size(); }
-
-QStringList FakeMetaEnum::keys() const
-{ return m_keys; }
-
-bool FakeMetaEnum::hasKey(const QString &key) const
-{ return m_keys.contains(key); }
-
-void FakeMetaEnum::addToHash(QCryptographicHash &hash) const
-{
- int len = m_name.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
- len = m_keys.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const QString &key, m_keys) {
- len = key.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
- }
-}
-
-QString FakeMetaEnum::describe(int baseIndent) const
-{
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Enum ");
- res += name();
- res += QLatin1String(": [");
- for (int i = 0; i < keyCount(); ++i) {
- res += newLine;
- res += QLatin1String(" ");
- res += key(i);
- }
- res += newLine;
- res += QLatin1Char(']');
- return res;
-}
-
-QString FakeMetaEnum::toString() const
-{
- return describe();
-}
-
-FakeMetaMethod::FakeMetaMethod(const QString &name, const QString &returnType)
- : m_name(name)
- , m_returnType(returnType)
- , m_methodTy(FakeMetaMethod::Method)
- , m_methodAccess(FakeMetaMethod::Public)
- , m_revision(0)
-{}
-
-FakeMetaMethod::FakeMetaMethod()
- : m_methodTy(FakeMetaMethod::Method)
- , m_methodAccess(FakeMetaMethod::Public)
- , m_revision(0)
-{}
-
-QString FakeMetaMethod::methodName() const
-{ return m_name; }
-
-void FakeMetaMethod::setMethodName(const QString &name)
-{ m_name = name; }
-
-void FakeMetaMethod::setReturnType(const QString &type)
-{ m_returnType = type; }
-
-QStringList FakeMetaMethod::parameterNames() const
-{ return m_paramNames; }
-
-QStringList FakeMetaMethod::parameterTypes() const
-{ return m_paramTypes; }
-
-void FakeMetaMethod::addParameter(const QString &name, const QString &type)
-{ m_paramNames.append(name); m_paramTypes.append(type); }
-
-int FakeMetaMethod::methodType() const
-{ return m_methodTy; }
-
-void FakeMetaMethod::setMethodType(int methodType)
-{ m_methodTy = methodType; }
-
-int FakeMetaMethod::access() const
-{ return m_methodAccess; }
-
-int FakeMetaMethod::revision() const
-{ return m_revision; }
-
-void FakeMetaMethod::setRevision(int r)
-{ m_revision = r; }
-
-void FakeMetaMethod::addToHash(QCryptographicHash &hash) const
-{
- int len = m_name.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_name.constData()), len * sizeof(QChar));
- hash.addData(reinterpret_cast<const char *>(&m_methodAccess), sizeof(m_methodAccess));
- hash.addData(reinterpret_cast<const char *>(&m_methodTy), sizeof(m_methodTy));
- hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
- len = m_paramNames.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const QString &pName, m_paramNames) {
- len = pName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(pName.constData()), len * sizeof(QChar));
- }
- len = m_paramTypes.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const QString &pType, m_paramTypes) {
- len = pType.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(pType.constData()), len * sizeof(QChar));
- }
- len = m_returnType.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_returnType.constData()), len * sizeof(QChar));
-}
-
-QString FakeMetaMethod::describe(int baseIndent) const
-{
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Method {");
- res += newLine;
- res += QLatin1String(" methodName:");
- res += methodName();
- res += newLine;
- res += QLatin1String(" methodType:");
- res += methodType();
- res += newLine;
- res += QLatin1String(" parameterNames:[");
- foreach (const QString &pName, parameterNames()) {
- res += newLine;
- res += QLatin1String(" ");
- res += pName;
- }
- res += QLatin1Char(']');
- res += newLine;
- res += QLatin1String(" parameterTypes:[");
- foreach (const QString &pType, parameterTypes()) {
- res += newLine;
- res += QLatin1String(" ");
- res += pType;
- }
- res += QLatin1Char(']');
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-QString FakeMetaMethod::toString() const
-{
- return describe();
-}
-
-
-FakeMetaProperty::FakeMetaProperty(const QString &name, const QString &type, bool isList,
- bool isWritable, bool isPointer, int revision)
- : m_propertyName(name)
- , m_type(type)
- , m_isList(isList)
- , m_isWritable(isWritable)
- , m_isPointer(isPointer)
- , m_revision(revision)
-{}
-
-QString FakeMetaProperty::name() const
-{ return m_propertyName; }
-
-QString FakeMetaProperty::typeName() const
-{ return m_type; }
-
-bool FakeMetaProperty::isList() const
-{ return m_isList; }
-
-bool FakeMetaProperty::isWritable() const
-{ return m_isWritable; }
-
-bool FakeMetaProperty::isPointer() const
-{ return m_isPointer; }
-
-int FakeMetaProperty::revision() const
-{ return m_revision; }
-
-void FakeMetaProperty::addToHash(QCryptographicHash &hash) const
-{
- int len = m_propertyName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_propertyName.constData()), len * sizeof(QChar));
- hash.addData(reinterpret_cast<const char *>(&m_revision), sizeof(m_revision));
- int flags = (m_isList ? (1 << 0) : 0)
- + (m_isPointer ? (1 << 1) : 0)
- + (m_isWritable ? (1 << 2) : 0);
- hash.addData(reinterpret_cast<const char *>(&flags), sizeof(flags));
- len = m_type.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_type.constData()), len * sizeof(QChar));
-}
-
-QString FakeMetaProperty::describe(int baseIndent) const
-{
- auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Property {");
- res += newLine;
- res += QLatin1String(" name:");
- res += name();
- res += newLine;
- res += QLatin1String(" typeName:");
- res += typeName();
- res += newLine;
- res += QLatin1String(" typeName:");
- res += QString::number(revision());
- res += newLine;
- res += QLatin1String(" isList:");
- res += boolStr(isList());
- res += newLine;
- res += QLatin1String(" isPointer:");
- res += boolStr(isPointer());
- res += newLine;
- res += QLatin1String(" isWritable:");
- res += boolStr(isWritable());
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-QString FakeMetaProperty::toString() const
-{
- return describe();
-}
-
-
-FakeMetaObject::FakeMetaObject() : m_isSingleton(false), m_isCreatable(true), m_isComposite(false)
-{
-}
-
-QString FakeMetaObject::className() const
-{ return m_className; }
-void FakeMetaObject::setClassName(const QString &name)
-{ m_className = name; }
-
-void FakeMetaObject::addExport(const QString &name, const QString &package, ComponentVersion version)
-{
- Export exp;
- exp.type = name;
- exp.package = package;
- exp.version = version;
- m_exports.append(exp);
-}
-
-void FakeMetaObject::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
-{
- m_exports[exportIndex].metaObjectRevision = metaObjectRevision;
-}
-
-QList<FakeMetaObject::Export> FakeMetaObject::exports() const
-{ return m_exports; }
-FakeMetaObject::Export FakeMetaObject::exportInPackage(const QString &package) const
-{
- foreach (const Export &exp, m_exports) {
- if (exp.package == package)
- return exp;
- }
- return Export();
-}
-
-void FakeMetaObject::setSuperclassName(const QString &superclass)
-{ m_superName = superclass; }
-QString FakeMetaObject::superclassName() const
-{ return m_superName; }
-
-void FakeMetaObject::addEnum(const FakeMetaEnum &fakeEnum)
-{ m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
-int FakeMetaObject::enumeratorCount() const
-{ return m_enums.size(); }
-int FakeMetaObject::enumeratorOffset() const
-{ return 0; }
-FakeMetaEnum FakeMetaObject::enumerator(int index) const
-{ return m_enums.at(index); }
-int FakeMetaObject::enumeratorIndex(const QString &name) const
-{ return m_enumNameToIndex.value(name, -1); }
-
-void FakeMetaObject::addProperty(const FakeMetaProperty &property)
-{ m_propNameToIdx.insert(property.name(), m_props.size()); m_props.append(property); }
-int FakeMetaObject::propertyCount() const
-{ return m_props.size(); }
-int FakeMetaObject::propertyOffset() const
-{ return 0; }
-FakeMetaProperty FakeMetaObject::property(int index) const
-{ return m_props.at(index); }
-int FakeMetaObject::propertyIndex(const QString &name) const
-{ return m_propNameToIdx.value(name, -1); }
-
-void FakeMetaObject::addMethod(const FakeMetaMethod &method)
-{ m_methods.append(method); }
-int FakeMetaObject::methodCount() const
-{ return m_methods.size(); }
-int FakeMetaObject::methodOffset() const
-{ return 0; }
-FakeMetaMethod FakeMetaObject::method(int index) const
-{ return m_methods.at(index); }
-int FakeMetaObject::methodIndex(const QString &name) const //If performances becomes an issue, just use a nameToIdx hash
-{
- for (int i=0; i<m_methods.count(); i++)
- if (m_methods[i].methodName() == name)
- return i;
- return -1;
-}
-
-QString FakeMetaObject::defaultPropertyName() const
-{ return m_defaultPropertyName; }
-void FakeMetaObject::setDefaultPropertyName(const QString &defaultPropertyName)
-{ m_defaultPropertyName = defaultPropertyName; }
-
-QString FakeMetaObject::attachedTypeName() const
-{ return m_attachedTypeName; }
-void FakeMetaObject::setAttachedTypeName(const QString &name)
-{ m_attachedTypeName = name; }
-
-QByteArray FakeMetaObject::calculateFingerprint() const
-{
- QCryptographicHash hash(QCryptographicHash::Sha1);
- int len = m_className.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_className.constData()), len * sizeof(QChar));
- len = m_attachedTypeName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_attachedTypeName.constData()), len * sizeof(QChar));
- len = m_defaultPropertyName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_defaultPropertyName.constData()), len * sizeof(QChar));
- len = m_enumNameToIndex.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- {
- QStringList keys(m_enumNameToIndex.keys());
- keys.sort();
- foreach (const QString &key, keys) {
- len = key.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
- int value = m_enumNameToIndex.value(key);
- hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
- m_enums.at(value).addToHash(hash);
- }
- }
- len = m_exports.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const Export &e, m_exports)
- e.addToHash(hash); // normalize order?
- len = m_exports.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- foreach (const FakeMetaMethod &m, m_methods)
- m.addToHash(hash); // normalize order?
- {
- QStringList keys(m_propNameToIdx.keys());
- keys.sort();
- foreach (const QString &key, keys) {
- len = key.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(key.constData()), len * sizeof(QChar));
- int value = m_propNameToIdx.value(key);
- hash.addData(reinterpret_cast<const char *>(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint...
- m_props.at(value).addToHash(hash);
- }
- }
- len = m_superName.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(m_superName.constData()), len * sizeof(QChar));
-
- QByteArray res = hash.result();
- res.append('F');
- return res;
-}
-
-void FakeMetaObject::updateFingerprint()
-{
- m_fingerprint = calculateFingerprint();
-}
-
-QByteArray FakeMetaObject::fingerprint() const
-{
- return m_fingerprint;
-}
-
-bool FakeMetaObject::isSingleton() const
-{
- return m_isSingleton;
-}
-
-bool FakeMetaObject::isCreatable() const
-{
- return m_isCreatable;
-}
-
-bool FakeMetaObject::isComposite() const
-{
- return m_isComposite;
-}
-
-void FakeMetaObject::setIsSingleton(bool value)
-{
- m_isSingleton = value;
-}
-
-void FakeMetaObject::setIsCreatable(bool value)
-{
- m_isCreatable = value;
-}
-
-void FakeMetaObject::setIsComposite(bool value)
-{
- m_isSingleton = value;
-}
-
-QString FakeMetaObject::toString() const
-{
- return describe();
-}
-
-QString FakeMetaObject::describe(bool printDetails, int baseIndent) const
-{
- QString res = QString::fromLatin1("FakeMetaObject@%1")
- .arg((quintptr)(void *)this, 0, 16);
- if (!printDetails)
- return res;
- auto boolStr = [] (bool v) { return v ? QLatin1String("true") : QLatin1String("false"); };
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- res += QLatin1Char('{');
- res += newLine;
- res += QLatin1String("className:");
- res += className();
- res += newLine;
- res += QLatin1String("superClassName:");
- res += superclassName();
- res += newLine;
- res += QLatin1String("isSingleton:");
- res += boolStr(isSingleton());
- res += newLine;
- res += QLatin1String("isCreatable:");
- res += boolStr(isCreatable());
- res += newLine;
- res += QLatin1String("isComposite:");
- res += boolStr(isComposite());
- res += newLine;
- res += QLatin1String("defaultPropertyName:");
- res += defaultPropertyName();
- res += newLine;
- res += QLatin1String("attachedTypeName:");
- res += attachedTypeName();
- res += newLine;
- res += QLatin1String("fingerprint:");
- res += QString::fromUtf8(fingerprint());
-
- res += newLine;
- res += QLatin1String("exports:[");
- foreach (const Export &e, exports()) {
- res += newLine;
- res += QLatin1String(" ");
- res += e.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
-
- res += newLine;
- res += QLatin1String("enums:[");
- for (int iEnum = 0; iEnum < enumeratorCount() ; ++ iEnum) {
- FakeMetaEnum e = enumerator(enumeratorOffset() + iEnum);
- res += newLine;
- res += QLatin1String(" ");
- res += e.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
-
- res += newLine;
- res += QLatin1String("properties:[");
- for (int iProp = 0; iProp < propertyCount() ; ++ iProp) {
- FakeMetaProperty prop = property(propertyOffset() + iProp);
- res += newLine;
- res += QLatin1String(" ");
- res += prop.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
- res += QLatin1String("methods:[");
- for (int iMethod = 0; iMethod < methodOffset() ; ++ iMethod) {
- FakeMetaMethod m = method(methodOffset() + iMethod);
- res += newLine;
- res += QLatin1String(" ");
- m.describe(baseIndent + 2);
- }
- res += QLatin1Char(']');
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-FakeMetaObject::Export::Export()
- : metaObjectRevision(0)
-{}
-bool FakeMetaObject::Export::isValid() const
-{ return version.isValid() || !package.isEmpty() || !type.isEmpty(); }
-
-void FakeMetaObject::Export::addToHash(QCryptographicHash &hash) const
-{
- int len = package.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(package.constData()), len * sizeof(QChar));
- len = type.size();
- hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
- hash.addData(reinterpret_cast<const char *>(type.constData()), len * sizeof(QChar));
- version.addToHash(hash);
- hash.addData(reinterpret_cast<const char *>(&metaObjectRevision), sizeof(metaObjectRevision));
-}
-
-QString FakeMetaObject::Export::describe(int baseIndent) const
-{
- QString newLine = QString::fromLatin1("\n") + QString::fromLatin1(" ").repeated(baseIndent);
- QString res = QLatin1String("Export {");
- res += newLine;
- res += QLatin1String(" package:");
- res += package;
- res += newLine;
- res += QLatin1String(" type:");
- res += type;
- res += newLine;
- res += QLatin1String(" version:");
- res += version.toString();
- res += newLine;
- res += QLatin1String(" metaObjectRevision:");
- res += QString::number(metaObjectRevision);
- res += newLine;
- res += QLatin1String(" isValid:");
- res += QString::number(isValid());
- res += newLine;
- res += QLatin1Char('}');
- return res;
-}
-
-QString FakeMetaObject::Export::toString() const
-{
- return describe();
-}
diff --git a/tools/qmllint/fakemetaobject.h b/tools/qmllint/fakemetaobject.h
deleted file mode 100644
index ae76596343..0000000000
--- a/tools/qmllint/fakemetaobject.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef FAKEMETAOBJECT_H
-#define FAKEMETAOBJECT_H
-
-#include <QString>
-#include <QStringList>
-#include <QList>
-#include <QHash>
-#include <QSharedPointer>
-
-#include "componentversion.h"
-
-QT_BEGIN_NAMESPACE
-class QCryptographicHash;
-QT_END_NAMESPACE
-
-namespace LanguageUtils {
-
-class FakeMetaEnum {
- QString m_name;
- QStringList m_keys;
-
-public:
- FakeMetaEnum();
- explicit FakeMetaEnum(const QString &name);
-
- bool isValid() const;
-
- QString name() const;
- void setName(const QString &name);
-
- void addKey(const QString &key);
- QString key(int index) const;
- int keyCount() const;
- QStringList keys() const;
- bool hasKey(const QString &key) const;
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
-};
-
-class FakeMetaMethod {
-public:
- enum {
- Signal,
- Slot,
- Method
- };
-
- enum {
- Private,
- Protected,
- Public
- };
-
-public:
- FakeMetaMethod();
- explicit FakeMetaMethod(const QString &name, const QString &returnType = QString());
-
- QString methodName() const;
- void setMethodName(const QString &name);
-
- void setReturnType(const QString &type);
-
- QStringList parameterNames() const;
- QStringList parameterTypes() const;
- void addParameter(const QString &name, const QString &type);
-
- int methodType() const;
- void setMethodType(int methodType);
-
- int access() const;
-
- int revision() const;
- void setRevision(int r);
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
-private:
- QString m_name;
- QString m_returnType;
- QStringList m_paramNames;
- QStringList m_paramTypes;
- int m_methodTy;
- int m_methodAccess;
- int m_revision;
-};
-
-class FakeMetaProperty {
- QString m_propertyName;
- QString m_type;
- bool m_isList;
- bool m_isWritable;
- bool m_isPointer;
- int m_revision;
-
-public:
- FakeMetaProperty(const QString &name, const QString &type, bool isList, bool isWritable, bool isPointer, int revision);
-
- QString name() const;
- QString typeName() const;
-
- bool isList() const;
- bool isWritable() const;
- bool isPointer() const;
- int revision() const;
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
-};
-
-class FakeMetaObject {
- Q_DISABLE_COPY(FakeMetaObject);
-
-public:
- typedef QSharedPointer<FakeMetaObject> Ptr;
- typedef QSharedPointer<const FakeMetaObject> ConstPtr;
-
- class Export {
- public:
- Export();
-
- QString package;
- QString type;
- ComponentVersion version;
- int metaObjectRevision;
-
- bool isValid() const;
- void addToHash(QCryptographicHash &hash) const;
-
- QString describe(int baseIndent = 0) const;
- QString toString() const;
- };
-
-private:
- QString m_className;
- QList<Export> m_exports;
- QString m_superName;
- QList<FakeMetaEnum> m_enums;
- QHash<QString, int> m_enumNameToIndex;
- QList<FakeMetaProperty> m_props;
- QHash<QString, int> m_propNameToIdx;
- QList<FakeMetaMethod> m_methods;
- QString m_defaultPropertyName;
- QString m_attachedTypeName;
- QByteArray m_fingerprint;
- bool m_isSingleton;
- bool m_isCreatable;
- bool m_isComposite;
-
-public:
- FakeMetaObject();
-
- QString className() const;
- void setClassName(const QString &name);
-
- void addExport(const QString &name, const QString &package, ComponentVersion version);
- void setExportMetaObjectRevision(int exportIndex, int metaObjectRevision);
- QList<Export> exports() const;
- Export exportInPackage(const QString &package) const;
-
- void setSuperclassName(const QString &superclass);
- QString superclassName() const;
-
- void addEnum(const FakeMetaEnum &fakeEnum);
- int enumeratorCount() const;
- int enumeratorOffset() const;
- FakeMetaEnum enumerator(int index) const;
- int enumeratorIndex(const QString &name) const;
-
- void addProperty(const FakeMetaProperty &property);
- int propertyCount() const;
- int propertyOffset() const;
- FakeMetaProperty property(int index) const;
- int propertyIndex(const QString &name) const;
-
- void addMethod(const FakeMetaMethod &method);
- int methodCount() const;
- int methodOffset() const;
- FakeMetaMethod method(int index) const;
- int methodIndex(const QString &name) const; // Note: Returns any method with that name in case of overloads
-
- QString defaultPropertyName() const;
- void setDefaultPropertyName(const QString &defaultPropertyName);
-
- QString attachedTypeName() const;
- void setAttachedTypeName(const QString &name);
- QByteArray calculateFingerprint() const;
- void updateFingerprint();
- QByteArray fingerprint() const;
-
- bool isSingleton() const;
- bool isCreatable() const;
- bool isComposite() const;
- void setIsSingleton(bool value);
- void setIsCreatable(bool value);
- void setIsComposite(bool value);
-
- QString describe(bool printDetails = true, int baseIndent = 0) const;
- QString toString() const;
-};
-
-} // namespace LanguageUtils
-
-#endif // FAKEMETAOBJECT_H
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
index d72f02b94a..ab7ff80609 100644
--- a/tools/qmllint/findunqualified.cpp
+++ b/tools/qmllint/findunqualified.cpp
@@ -28,18 +28,17 @@
#include "findunqualified.h"
#include "scopetree.h"
+#include "typedescriptionreader.h"
-#include "qmljstypedescriptionreader.h"
+#include <QtQml/private/qqmljsast_p.h>
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qv4codegen_p.h>
+#include <QtQml/private/qqmldirparser_p.h>
-#include <QFile>
-#include <QDirIterator>
-#include <QScopedValueRollback>
-
-#include <private/qqmljsast_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qv4codegen_p.h>
-#include <private/qqmldirparser_p.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qscopedvaluerollback.h>
static QQmlDirParser createQmldirParserForFile(const QString &filename)
{
@@ -50,17 +49,17 @@ static QQmlDirParser createQmldirParserForFile(const QString &filename)
return parser;
}
-static QQmlJS::TypeDescriptionReader createQmltypesReaderForFile(QString const &filename)
+static TypeDescriptionReader createQmltypesReaderForFile(const QString &filename)
{
QFile f(filename);
f.open(QFile::ReadOnly);
- QQmlJS::TypeDescriptionReader reader { filename, f.readAll() };
+ TypeDescriptionReader reader { filename, f.readAll() };
return reader;
}
void FindUnqualifiedIDVisitor::enterEnvironment(ScopeType type, QString name)
{
- m_currentScope = m_currentScope->createNewChildScope(type, name);
+ m_currentScope = m_currentScope->createNewChildScope(type, std::move(name));
}
void FindUnqualifiedIDVisitor::leaveEnvironment()
@@ -70,7 +69,8 @@ void FindUnqualifiedIDVisitor::leaveEnvironment()
enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned, BasePath };
-QStringList completeImportPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
+QStringList completeImportPaths(const QString &uri, const QStringList &basePaths,
+ int vmaj, int vmin)
{
static const QLatin1Char Slash('/');
static const QLatin1Char Backslash('\\');
@@ -85,15 +85,16 @@ QStringList completeImportPaths(const QString &uri, const QStringList &basePaths
{
if (version == FullyVersioned) {
// extension with fully encoded version number (eg. MyModule.3.2)
- return QString::asprintf(".%d.%d", vmaj, vmin);
- } else if (version == PartiallyVersioned) {
+ return QString::fromLatin1(".%1.%2").arg(vmaj).arg(vmin);
+ }
+ if (version == PartiallyVersioned) {
// extension with encoded version major (eg. MyModule.3)
- return QString::asprintf(".%d", vmaj);
- } // else extension without version number (eg. MyModule)
+ return QString::fromLatin1(".%1").arg(vmaj);
+ }
+ // else extension without version number (eg. MyModule)
return QString();
};
- auto joinStringRefs = [](const QVector<QStringRef> &refs, const QChar &sep)
- {
+ auto joinStringRefs = [](const QVector<QStringRef> &refs, const QChar &sep) {
QString str;
for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
if (it != refs.cbegin())
@@ -131,19 +132,19 @@ QStringList completeImportPaths(const QString &uri, const QStringList &basePaths
return qmlDirPathsPaths;
}
-void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int major, int minor)
+void FindUnqualifiedIDVisitor::importHelper(QString id, const QString &prefix, int major, int minor)
{
QPair<QString, QString> importId { id, prefix };
- if (m_alreadySeenImports.contains(importId)) {
+ if (m_alreadySeenImports.contains(importId))
return;
- } else {
- m_alreadySeenImports.insert(importId);
- }
+
+ m_alreadySeenImports.insert(importId);
+
id = id.replace(QLatin1String("/"), QLatin1String("."));
auto qmltypesPaths = completeImportPaths(id, m_qmltypeDirs, major, minor);
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> objects;
- QList<QQmlJS::ModuleApiInfo> moduleApis;
+ QHash<QString, ScopeTree::ConstPtr> objects;
+ QList<ModuleApiInfo> moduleApis;
QStringList dependencies;
static const QLatin1String SlashPluginsDotQmltypes("/plugins.qmltypes");
static const QLatin1String SlashQmldir("/qmldir");
@@ -154,7 +155,7 @@ void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int majo
for (const QString &import : imports)
importHelper(import, prefix, major, minor);
- QHash<QString, LanguageUtils::FakeMetaObject *> qmlComponents;
+ QHash<QString, ScopeTree *> qmlComponents;
const auto components = reader.components();
for (auto it = components.begin(), end = components.end(); it != end; ++it) {
const QString filePath = qmltypesPath + QLatin1Char('/') + it->fileName;
@@ -168,15 +169,15 @@ void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int majo
auto mo = qmlComponents.find(it.key());
if (mo == qmlComponents.end())
- mo = qmlComponents.insert(it.key(), localQmlFile2FakeMetaObject(filePath));
+ mo = qmlComponents.insert(it.key(), localQmlFile2ScopeTree(filePath));
(*mo)->addExport(
it.key(), reader.typeNamespace(),
- LanguageUtils::ComponentVersion(it->majorVersion, it->minorVersion));
+ ComponentVersion(it->majorVersion, it->minorVersion));
}
for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it) {
objects.insert(it.key(),
- QSharedPointer<const LanguageUtils::FakeMetaObject>(it.value()));
+ QSharedPointer<const ScopeTree>(it.value()));
}
}
if (QFile::exists(qmltypesPath + SlashPluginsDotQmltypes)) {
@@ -188,7 +189,7 @@ void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int majo
}
for (auto const &dependency : qAsConst(dependencies)) {
auto const split = dependency.split(" ");
- auto const id = split.at(0);
+ auto const &id = split.at(0);
auto const major = split.at(1).split('.').at(0).toInt();
auto const minor = split.at(1).split('.').at(1).toInt();
importHelper(id, QString(), major, minor);
@@ -196,27 +197,28 @@ void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int majo
// add objects
for (auto ob_it = objects.begin(); ob_it != objects.end(); ++ob_it) {
auto val = ob_it.value();
- m_exportedName2MetaObject[prefix + val->className()] = val;
- for (auto export_ : val->exports()) {
- m_exportedName2MetaObject[prefix + export_.type] = val;
- }
- for (auto enumCount = 0; enumCount < val->enumeratorCount(); ++enumCount) {
- m_currentScope->insertQMLIdentifier(val->enumerator(enumCount).name());
- }
+ m_exportedName2Scope[prefix + val->className()] = val;
+
+ const auto exports = val->exports();
+ for (const auto &valExport : exports)
+ m_exportedName2Scope[prefix + valExport.type()] = val;
+
+ const auto enums = val->enums();
+ for (const auto &valEnum : enums)
+ m_currentScope->addEnum(valEnum);
}
}
-LanguageUtils::FakeMetaObject *
-FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
+ScopeTree *FindUnqualifiedIDVisitor::localQmlFile2ScopeTree(const QString &filePath)
{
using namespace QQmlJS::AST;
- auto fake = new LanguageUtils::FakeMetaObject;
+ auto scope = new ScopeTree(ScopeType::QMLScope);
QString baseName = QFileInfo { filePath }.baseName();
- fake->setClassName(baseName.endsWith(".ui") ? baseName.chopped(3) : baseName);
+ scope->setClassName(baseName.endsWith(".ui") ? baseName.chopped(3) : baseName);
QFile file(filePath);
- if (!file.open(QFile::ReadOnly)) {
- return fake;
- }
+ if (!file.open(QFile::ReadOnly))
+ return scope;
+
QString code = file.readAll();
file.close();
@@ -226,7 +228,7 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
lexer.setCode(code, 1, true);
QQmlJS::Parser parser(&engine);
if (!parser.parse()) {
- return fake;
+ return scope;
}
QQmlJS::AST::UiProgram *program = parser.ast();
auto header = program->headers;
@@ -245,7 +247,8 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
if (import->asToken.isValid()) {
prefix += import->importId + QLatin1Char('.');
}
- importHelper(path, prefix, import->version->majorVersion, import->version->minorVersion);
+ importHelper(path, prefix, import->version->majorVersion,
+ import->version->minorVersion);
}
}
header = header->next;
@@ -254,12 +257,12 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
// member should be the sole element
Q_ASSERT(!member->next);
Q_ASSERT(member && member->member->kind == UiObjectMember::Kind_UiObjectDefinition);
- auto definition = static_cast<UiObjectDefinition *>(member->member);
+ auto definition = cast<UiObjectDefinition *>(member->member);
auto qualifiedId = definition->qualifiedTypeNameId;
while (qualifiedId && qualifiedId->next) {
qualifiedId = qualifiedId->next;
}
- fake->setSuperclassName(qualifiedId->name.toString());
+ scope->setSuperclassName(qualifiedId->name.toString());
UiObjectMemberList *initMembers = definition->initializer->members;
while (initMembers) {
switch (initMembers->member->kind) {
@@ -280,28 +283,30 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
break;
}
case UiObjectMember::Kind_UiPublicMember: {
- auto publicMember = static_cast<UiPublicMember *>(initMembers->member);
+ auto publicMember = cast<UiPublicMember *>(initMembers->member);
switch (publicMember->type) {
case UiPublicMember::Signal: {
UiParameterList *param = publicMember->parameters;
- LanguageUtils::FakeMetaMethod method;
- method.setMethodType(LanguageUtils::FakeMetaMethod::Signal);
+ MetaMethod method;
+ method.setMethodType(MetaMethod::Signal);
method.setMethodName(publicMember->name.toString());
while (param) {
method.addParameter(param->name.toString(), param->type->name.toString());
param = param->next;
}
- fake->addMethod(method);
+ scope->addMethod(method);
break;
}
case UiPublicMember::Property: {
- LanguageUtils::FakeMetaProperty fakeprop { publicMember->name.toString(),
- publicMember->typeModifier.toString(),
- false,
- false,
- false,
- 0 };
- fake->addProperty(fakeprop);
+ const MetaProperty property {
+ publicMember->name.toString(),
+ publicMember->typeModifier.toString(),
+ false,
+ false,
+ false,
+ 0
+ };
+ scope->addProperty(property);
break;
}
}
@@ -312,24 +317,21 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
break;
}
case UiObjectMember::Kind_UiSourceElement: {
- auto sourceElement = static_cast<UiSourceElement *>(initMembers->member);
+ auto sourceElement = cast<UiSourceElement *>(initMembers->member);
if (FunctionExpression *fexpr = sourceElement->sourceElement->asFunctionDefinition()) {
- LanguageUtils::FakeMetaMethod method;
+ MetaMethod method;
method.setMethodName(fexpr->name.toString());
- method.setMethodType(LanguageUtils::FakeMetaMethod::Method);
+ method.setMethodType(MetaMethod::Method);
FormalParameterList *parameters = fexpr->formals;
while (parameters) {
- method.addParameter(parameters->element->bindingIdentifier.toString(),
- "");
+ method.addParameter(parameters->element->bindingIdentifier.toString(), "");
parameters = parameters->next;
}
- fake->addMethod(method);
+ scope->addMethod(method);
} else if (ClassExpression *clexpr =
sourceElement->sourceElement->asClassDefinition()) {
- LanguageUtils::FakeMetaProperty prop {
- clexpr->name.toString(), "", false, false, false, 1
- };
- fake->addProperty(prop);
+ const MetaProperty prop { clexpr->name.toString(), "", false, false, false, 1 };
+ scope->addProperty(prop);
} else if (cast<VariableStatement *>(sourceElement->sourceElement)) {
// nothing to do
} else {
@@ -348,7 +350,7 @@ FindUnqualifiedIDVisitor::localQmlFile2FakeMetaObject(QString filePath)
}
initMembers = initMembers->next;
}
- return fake;
+ return scope;
}
void FindUnqualifiedIDVisitor::importDirectory(const QString &directory, const QString &prefix)
@@ -360,34 +362,30 @@ void FindUnqualifiedIDVisitor::importDirectory(const QString &directory, const Q
QDirIterator it { dirname, QStringList() << QLatin1String("*.qml"), QDir::NoFilter };
while (it.hasNext()) {
- LanguageUtils::FakeMetaObject *fake = localQmlFile2FakeMetaObject(it.next());
- m_exportedName2MetaObject.insert(
- prefix + fake->className(),
- QSharedPointer<const LanguageUtils::FakeMetaObject>(fake));
+ const ScopeTree *scope = localQmlFile2ScopeTree(it.next());
+ m_exportedName2Scope.insert(prefix + scope->className(), ScopeTree::ConstPtr(scope));
}
}
-void FindUnqualifiedIDVisitor::importExportedNames(QStringRef prefix, QString name)
+void FindUnqualifiedIDVisitor::importExportedNames(const QStringRef &prefix, QString name)
{
for (;;) {
- auto metaObject = m_exportedName2MetaObject[m_exportedName2MetaObject.contains(name)
+ auto scope = m_exportedName2Scope[m_exportedName2Scope.contains(name)
? name
: prefix + QLatin1Char('.') + name];
- if (metaObject) {
- auto propertyCount = metaObject->propertyCount();
- for (auto i = 0; i < propertyCount; ++i) {
- m_currentScope->insertPropertyIdentifier(metaObject->property(i).name());
- }
-
- m_currentScope->addMethodsFromMetaObject(metaObject);
-
- name = metaObject->superclassName();
- if (name.isEmpty() || name == QLatin1String("QObject")) {
+ if (scope) {
+ const auto properties = scope->properties();
+ for (const auto &property : properties)
+ m_currentScope->insertPropertyIdentifier(property);
+
+ m_currentScope->addMethods(scope->methods());
+ name = scope->superclassName();
+ if (name.isEmpty() || name == QLatin1String("QObject"))
break;
- }
} else {
m_colorOut.write(QLatin1String("warning: "), Warning);
- m_colorOut.write(name + QLatin1String(" was not found. Did you add all import paths?\n"));
+ m_colorOut.write(name + QLatin1String(" was not found."
+ " Did you add all import paths?\n"));
m_unknownImports.insert(name);
break;
}
@@ -404,8 +402,8 @@ void FindUnqualifiedIDVisitor::throwRecursionDepthError()
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiProgram *)
{
enterEnvironment(ScopeType::QMLScope, "program");
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> objects;
- QList<QQmlJS::ModuleApiInfo> moduleApis;
+ QHash<QString, ScopeTree::ConstPtr> objects;
+ QList<ModuleApiInfo> moduleApis;
QStringList dependencies;
for (auto const &dir : m_qmltypeDirs) {
QDirIterator it { dir, QStringList() << QLatin1String("builtins.qmltypes"), QDir::NoFilter,
@@ -420,25 +418,27 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiProgram *)
// add builtins
for (auto ob_it = objects.begin(); ob_it != objects.end(); ++ob_it) {
auto val = ob_it.value();
- for (auto export_ : val->exports()) {
- m_exportedName2MetaObject[export_.type] = val;
- }
- for (auto enumCount = 0; enumCount < val->enumeratorCount(); ++enumCount) {
- m_currentScope->insertQMLIdentifier(val->enumerator(enumCount).name());
- }
+
+ const auto exports = val->exports();
+ for (const auto &valExport : exports)
+ m_exportedName2Scope[valExport.type()] = val;
+
+ const auto enums = val->enums();
+ for (const auto &valEnum : enums)
+ m_currentScope->addEnum(valEnum);
}
// add "self" (as we only ever check the first part of a qualified identifier, we get away with
- // using an empty FakeMetaObject
- m_exportedName2MetaObject[QFileInfo { m_filePath }.baseName()] = {};
+ // using an empty ScopeTree
+ m_exportedName2Scope[QFileInfo { m_filePath }.baseName()] = {};
// add QML builtins
- m_exportedName2MetaObject["QtObject"] = {}; // QtObject contains nothing of interest
+ m_exportedName2Scope["QtObject"] = {}; // QtObject contains nothing of interest
- LanguageUtils::FakeMetaObject *meta = new LanguageUtils::FakeMetaObject{};
- meta->addProperty(LanguageUtils::FakeMetaProperty {"enabled", "bool", false, false, false, 0});
- meta->addProperty(LanguageUtils::FakeMetaProperty {"ignoreUnknownSignals", "bool", false, false, false, 0});
- meta->addProperty(LanguageUtils::FakeMetaProperty {"target", "QObject", false, false, false, 0});
- m_exportedName2MetaObject["Connections"] = LanguageUtils::FakeMetaObject::ConstPtr { meta };
+ ScopeTree *scope = new ScopeTree(ScopeType::QMLScope);
+ scope->addProperty(MetaProperty {"enabled", "bool", false, false, false, 0});
+ scope->addProperty(MetaProperty {"ignoreUnknownSignals", "bool", false, false, false, 0});
+ scope->addProperty(MetaProperty {"target", "QObject", false, false, false, 0});
+ m_exportedName2Scope["Connections"] = ScopeTree::ConstPtr { scope };
importDirectory(".", QString());
return true;
@@ -518,7 +518,8 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::CaseBlock *)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::Catch *catchStatement)
{
enterEnvironment(ScopeType::JSLexicalScope, "catch");
- m_currentScope->insertJSIdentifier(catchStatement->patternElement->bindingIdentifier.toString(), QQmlJS::AST::VariableScope::Let);
+ m_currentScope->insertJSIdentifier(catchStatement->patternElement->bindingIdentifier.toString(),
+ QQmlJS::AST::VariableScope::Let);
return true;
}
@@ -529,8 +530,13 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::Catch *)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::WithStatement *withStatement)
{
- m_colorOut.write(QString::asprintf("Warning: "), Warning);
- m_colorOut.write(QString::asprintf("%d:%d: with statements are strongly discouraged in QML and might cause false positives when analysing unqalified identifiers\n", withStatement->firstSourceLocation().startLine, withStatement->firstSourceLocation().startColumn), Normal);
+ m_colorOut.write(QString::fromLatin1("Warning: "), Warning);
+ m_colorOut.write(QString::fromLatin1(
+ "%1:%2: with statements are strongly discouraged in QML "
+ "and might cause false positives when analysing unqalified identifiers\n")
+ .arg(withStatement->firstSourceLocation().startLine)
+ .arg(withStatement->firstSourceLocation().startColumn),
+ Normal);
enterEnvironment(ScopeType::JSLexicalScope, "with");
return true;
}
@@ -563,13 +569,12 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
auto name = uisb->qualifiedId->name;
if (name == QLatin1String("id")) {
// found id
- auto expstat = static_cast<ExpressionStatement *>(uisb->statement);
- auto identexp = static_cast<IdentifierExpression *>(expstat->expression);
+ auto expstat = cast<ExpressionStatement *>(uisb->statement);
+ auto identexp = cast<IdentifierExpression *>(expstat->expression);
QString elementName = m_currentScope->name();
- m_qmlid2meta.insert(identexp->name.toString(), m_exportedName2MetaObject[elementName]);
- if (m_currentScope->isVisualRootScope()) {
+ m_qmlid2scope.insert(identexp->name.toString(), m_exportedName2Scope[elementName]);
+ if (m_currentScope->isVisualRootScope())
m_rootId = identexp->name.toString();
- }
} else {
const QString signal = signalName(name);
if (signal.isEmpty())
@@ -582,7 +587,7 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
const auto statement = uisb->statement;
if (statement->kind == Node::Kind::Kind_ExpressionStatement) {
- if (static_cast<ExpressionStatement *>(statement)->expression->asFunctionDefinition()) {
+ if (cast<ExpressionStatement *>(statement)->expression->asFunctionDefinition()) {
// functions are already handled
// they do not get names inserted according to the signal, but access their formal
// parameters
@@ -607,37 +612,42 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiPublicMember *uipm)
{
// property bool inactive: !active
// extract name inactive
- m_currentScope->insertPropertyIdentifier(uipm->name.toString());
+ m_currentScope->insertPropertyIdentifier(MetaProperty(
+ uipm->name.toString(),
+ // TODO: signals, complex types etc.
+ uipm->memberType ? uipm->memberType->name.toString() : QString(),
+ uipm->typeModifier == QLatin1String("list"),
+ !uipm->isReadonlyMember,
+ false, 0));
return true;
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::IdentifierExpression *idexp)
{
auto name = idexp->name;
- if (!m_exportedName2MetaObject.contains(name.toString())) {
+ if (!m_exportedName2Scope.contains(name.toString())) {
m_currentScope->addIdToAccssedIfNotInParentScopes(
{ name.toString(), idexp->firstSourceLocation() }, m_unknownImports);
}
return true;
}
-FindUnqualifiedIDVisitor::FindUnqualifiedIDVisitor(QStringList const &qmltypeDirs,
- const QString &code, const QString &fileName,
- bool silent)
+FindUnqualifiedIDVisitor::FindUnqualifiedIDVisitor(QStringList qmltypeDirs, QString code,
+ QString fileName, bool silent)
: m_rootScope(new ScopeTree { ScopeType::JSFunctionScope, "global" }),
m_currentScope(m_rootScope.get()),
- m_qmltypeDirs(qmltypeDirs),
- m_code(code),
+ m_qmltypeDirs(std::move(qmltypeDirs)),
+ m_code(std::move(code)),
m_rootId(QLatin1String("<id>")),
- m_filePath(fileName),
+ m_filePath(std::move(fileName)),
m_colorOut(silent)
{
// setup color output
- m_colorOut.insertColorMapping(Error, ColorOutput::RedForeground);
- m_colorOut.insertColorMapping(Warning, ColorOutput::PurpleForeground);
- m_colorOut.insertColorMapping(Info, ColorOutput::BlueForeground);
- m_colorOut.insertColorMapping(Normal, ColorOutput::DefaultColor);
- m_colorOut.insertColorMapping(Hint, ColorOutput::GreenForeground);
+ m_colorOut.insertMapping(Error, ColorOutput::RedForeground);
+ m_colorOut.insertMapping(Warning, ColorOutput::PurpleForeground);
+ m_colorOut.insertMapping(Info, ColorOutput::BlueForeground);
+ m_colorOut.insertMapping(Normal, ColorOutput::DefaultColor);
+ m_colorOut.insertMapping(Hint, ColorOutput::GreenForeground);
QLatin1String jsGlobVars[] = {
/* Not listed on the MDN page; browser and QML extensions: */
// console/debug api
@@ -645,32 +655,36 @@ FindUnqualifiedIDVisitor::FindUnqualifiedIDVisitor(QStringList const &qmltypeDir
// garbage collector
QLatin1String("gc"),
// i18n
- QLatin1String("qsTr"), QLatin1String("qsTrId"), QLatin1String("QT_TR_NOOP"), QLatin1String("QT_TRANSLATE_NOOP"), QLatin1String("QT_TRID_NOOP"),
+ QLatin1String("qsTr"), QLatin1String("qsTrId"), QLatin1String("QT_TR_NOOP"),
+ QLatin1String("QT_TRANSLATE_NOOP"), QLatin1String("QT_TRID_NOOP"),
// XMLHttpRequest
QLatin1String("XMLHttpRequest")
};
- for (const char **globalName = QV4::Compiler::Codegen::s_globalNames; *globalName != nullptr; ++globalName) {
- m_currentScope->insertJSIdentifier(QString::fromLatin1(*globalName), QQmlJS::AST::VariableScope::Const);
+ for (const char **globalName = QV4::Compiler::Codegen::s_globalNames;
+ *globalName != nullptr;
+ ++globalName) {
+ m_currentScope->insertJSIdentifier(QString::fromLatin1(*globalName),
+ QQmlJS::AST::VariableScope::Const);
}
for (const auto& jsGlobVar: jsGlobVars)
m_currentScope->insertJSIdentifier(jsGlobVar, QQmlJS::AST::VariableScope::Const);
}
-FindUnqualifiedIDVisitor::~FindUnqualifiedIDVisitor() = default;
-
bool FindUnqualifiedIDVisitor::check()
{
if (m_visitFailed)
return false;
// now that all ids are known, revisit any Connections whose target were perviously unknown
- for (auto const& outstandingConnection: m_outstandingConnections) {
- auto metaObject = m_qmlid2meta[outstandingConnection.targetName];
- outstandingConnection.scope->addMethodsFromMetaObject(metaObject);
+ for (auto const &outstandingConnection: m_outstandingConnections) {
+ auto targetScope = m_qmlid2scope[outstandingConnection.targetName];
+ if (outstandingConnection.scope)
+ outstandingConnection.scope->addMethods(targetScope->methods());
QScopedValueRollback<ScopeTree*> rollback(m_currentScope, outstandingConnection.scope);
outstandingConnection.uiod->initializer->accept(this);
}
- return m_rootScope->recheckIdentifiers(m_code, m_qmlid2meta, m_rootScope.get(), m_rootId, m_colorOut);
+ return m_rootScope->recheckIdentifiers(m_code, m_qmlid2scope, m_rootScope.get(), m_rootId,
+ m_colorOut);
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::VariableDeclarationList *vdl)
@@ -686,18 +700,16 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::VariableDeclarationList *vdl)
void FindUnqualifiedIDVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr)
{
using namespace QQmlJS::AST;
- if (!fexpr->name.isEmpty()) {
- auto name = fexpr->name.toString();
- if (m_currentScope->scopeType() == ScopeType::QMLScope) {
- m_currentScope->insertQMLIdentifier(name);
- } else {
+ auto name = fexpr->name.toString();
+ if (!name.isEmpty()) {
+ if (m_currentScope->scopeType() == ScopeType::QMLScope)
+ m_currentScope->addMethod(MetaMethod(name, QLatin1String("void")));
+ else
m_currentScope->insertJSIdentifier(name, VariableScope::Const);
- }
+ enterEnvironment(ScopeType::JSFunctionScope, name);
+ } else {
+ enterEnvironment(ScopeType::JSFunctionScope, QLatin1String("<anon>"));
}
- QString name = fexpr->name.toString();
- if (name.isEmpty())
- name = "<anon>";
- enterEnvironment(ScopeType::JSFunctionScope, name);
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::FunctionExpression *fexpr)
@@ -743,7 +755,8 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiImport *import)
QString path {};
if (!import->importId.isEmpty()) {
- m_qmlid2meta.insert(import->importId.toString(), {}); // TODO: do not put imported ids into the same space as qml IDs
+ // TODO: do not put imported ids into the same space as qml IDs
+ m_qmlid2scope.insert(import->importId.toString(), {});
}
if (import->version) {
auto uri = import->importUri;
@@ -761,14 +774,17 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiImport *import)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
{
- m_currentScope->insertQMLIdentifier(uied->name.toString());
+ MetaEnum qmlEnum(uied->name.toString());
+ for (const auto *member = uied->members; member; member = member->next)
+ qmlEnum.addKey(member->member.toString());
+ m_currentScope->addEnum(qmlEnum);
return true;
}
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
{
// property QtObject __styleData: QtObject {...}
- m_currentScope->insertPropertyIdentifier(uiob->qualifiedId->name.toString());
+
QString name {};
auto id = uiob->qualifiedTypeNameId;
QStringRef prefix = uiob->qualifiedTypeNameId->name;
@@ -777,8 +793,13 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
id = id->next;
}
name.chop(1);
+
+ const MetaProperty prop(uiob->qualifiedId->name.toString(), name, false, true, true, 0);
+ m_currentScope->addProperty(prop);
+
enterEnvironment(ScopeType::QMLScope, name);
- if (name == QLatin1String("Component") || name == QLatin1String("QtObject")) // there is no typeinfo for Component and QtObject, but they also have no interesting properties
+ // there is no typeinfo for Component and QtObject, but they also have no interesting properties
+ if (name == QLatin1String("Component") || name == QLatin1String("QtObject"))
return true;
importExportedNames(prefix, name);
return true;
@@ -791,6 +812,8 @@ void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::UiObjectBinding *)
bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
{
+ using namespace QQmlJS::AST;
+
QString name {};
auto id = uiod->qualifiedTypeNameId;
QStringRef prefix = uiod->qualifiedTypeNameId->name;
@@ -802,8 +825,11 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
enterEnvironment(ScopeType::QMLScope, name);
if (name.isLower())
return false; // Ignore grouped properties for now
- if (name == QLatin1String("Component") || name == QLatin1String("QtObject")) // there is no typeinfo for Component
+
+ // there is no typeinfo for Component
+ if (name == QLatin1String("Component") || name == QLatin1String("QtObject"))
return true;
+
importExportedNames(prefix, name);
if (name.endsWith("Connections")) {
QString target;
@@ -825,25 +851,26 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
}
member = member->next;
}
- LanguageUtils::FakeMetaObject::ConstPtr metaObject {};
+ ScopeTree::ConstPtr targetScope;
if (target.isEmpty()) {
// no target set, connection comes from parentF
ScopeTree* scope = m_currentScope;
do {
scope = scope->parentScope(); // TODO: rename method
} while (scope->scopeType() != ScopeType::QMLScope);
- auto metaObject = m_exportedName2MetaObject[scope->name()];
+ targetScope = m_exportedName2Scope[scope->name()];
} else {
// there was a target, check if we already can find it
- auto metaObjectIt = m_qmlid2meta.find(target);
- if (metaObjectIt != m_qmlid2meta.end()) {
- metaObject = *metaObjectIt;
+ auto scopeIt = m_qmlid2scope.find(target);
+ if (scopeIt != m_qmlid2scope.end()) {
+ targetScope = *scopeIt;
} else {
m_outstandingConnections.push_back({target, m_currentScope, uiod});
return false; // visit children later once target is known
}
}
- m_currentScope->addMethodsFromMetaObject(metaObject);
+ if (targetScope)
+ m_currentScope->addMethods(targetScope->methods());
}
return true;
}
diff --git a/tools/qmllint/findunqualified.h b/tools/qmllint/findunqualified.h
index 80413bd402..8b79918d90 100644
--- a/tools/qmllint/findunqualified.h
+++ b/tools/qmllint/findunqualified.h
@@ -29,32 +29,41 @@
#ifndef FINDUNQUALIFIED_H
#define FINDUNQUALIFIED_H
-#include "qmljstypedescriptionreader.h"
-#include "qcoloroutput_p.h"
-
-#include <private/qqmljsastvisitor_p.h>
-#include <private/qqmljsast_p.h>
-
-#include <QScopedPointer>
-
-class ScopeTree;
-enum class ScopeType;
-
-class FindUnqualifiedIDVisitor : public QQmlJS::AST::Visitor {
-
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include "typedescriptionreader.h"
+#include "scopetree.h"
+#include "qcoloroutput.h"
+
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+#include <QtCore/qscopedpointer.h>
+
+class FindUnqualifiedIDVisitor : public QQmlJS::AST::Visitor
+{
+ Q_DISABLE_COPY_MOVE(FindUnqualifiedIDVisitor)
public:
- explicit FindUnqualifiedIDVisitor(QStringList const &qmltypeDirs, const QString& code,
- const QString& fileName, bool silent);
- ~FindUnqualifiedIDVisitor() override;
+ explicit FindUnqualifiedIDVisitor(QStringList qmltypeDirs, QString code,
+ QString fileName, bool silent);
+ ~FindUnqualifiedIDVisitor() override = default;
bool check();
private:
QScopedPointer<ScopeTree> m_rootScope;
- ScopeTree *m_currentScope;
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> m_exportedName2MetaObject;
+ ScopeTree *m_currentScope = nullptr;
+ QHash<QString, ScopeTree::ConstPtr> m_exportedName2Scope;
QStringList m_qmltypeDirs;
- const QString& m_code;
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> m_qmlid2meta;
+ QString m_code;
+ QHash<QString, ScopeTree::ConstPtr> m_qmlid2scope;
QString m_rootId;
QString m_filePath;
QSet<QPair<QString, QString>> m_alreadySeenImports;
@@ -62,17 +71,22 @@ private:
ColorOutput m_colorOut;
bool m_visitFailed = false;
- struct OutstandingConnection {QString targetName; ScopeTree *scope; QQmlJS::AST::UiObjectDefinition *uiod;};
+ struct OutstandingConnection
+ {
+ QString targetName;
+ ScopeTree *scope;
+ QQmlJS::AST::UiObjectDefinition *uiod;
+ };
QVarLengthArray<OutstandingConnection, 3> m_outstandingConnections; // Connections whose target we have not encountered
void enterEnvironment(ScopeType type, QString name);
void leaveEnvironment();
- void importHelper(QString id, QString prefix, int major, int minor);
- LanguageUtils::FakeMetaObject* localQmlFile2FakeMetaObject(QString filePath);
+ void importHelper(QString id, const QString &prefix, int major, int minor);
+ ScopeTree* localQmlFile2ScopeTree(const QString &filePath);
void importDirectory(const QString &directory, const QString &prefix);
- void importExportedNames(QStringRef prefix, QString name);
+ void importExportedNames(const QStringRef &prefix, QString name);
void throwRecursionDepthError() override;
@@ -130,5 +144,4 @@ private:
bool visit(QQmlJS::AST::PatternElement *) override;
};
-
#endif // FINDUNQUALIFIED_H
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 232b31934e..0a0e669e94 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -26,27 +26,29 @@
**
****************************************************************************/
-#include <QDebug>
-#include <QFile>
-#include <QFileInfo>
+#include "findunqualified.h"
+
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
+#include <QtQml/private/qqmljsastvisitor_p.h>
+#include <QtQml/private/qqmljsast_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qcoreapplication.h>
+
#if QT_CONFIG(commandlineparser)
-#include <QCommandLineParser>
+#include <QtCore/qcommandlineparser.h>
#endif
-#include <QCoreApplication>
#ifndef QT_BOOTSTRAPPED
-#include <QLibraryInfo>
+#include <QtCore/qlibraryinfo.h>
#endif
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljsengine_p.h>
-#include <private/qqmljsastvisitor_p.h>
-#include <private/qqmljsast_p.h>
-
-#include "findunqualified.h"
-
-static bool lint_file(const QString &filename, const bool silent, const bool warnUnqualied, QStringList const &qmltypeDirs)
+static bool lint_file(const QString &filename, const bool silent, const bool warnUnqualied,
+ const QStringList &qmltypeDirs)
{
QFile file(filename);
if (!file.open(QFile::ReadOnly)) {
@@ -63,17 +65,20 @@ static bool lint_file(const QString &filename, const bool silent, const bool war
QFileInfo info(filename);
const QString lowerSuffix = info.suffix().toLower();
- const bool isJavaScript = (lowerSuffix == QLatin1String("js") || lowerSuffix == QLatin1String("mjs"));
const bool isESModule = lowerSuffix == QLatin1String("mjs");
- lexer.setCode(code, /*line = */ 1, /*qmlMode=*/ !isJavaScript);
+ const bool isJavaScript = isESModule || lowerSuffix == QLatin1String("js");
+
+ lexer.setCode(code, /*lineno = */ 1, /*qmlMode=*/ !isJavaScript);
QQmlJS::Parser parser(&engine);
- bool success = isJavaScript ? (isESModule ? parser.parseModule() : parser.parseProgram()) : parser.parse();
+ bool success = isJavaScript ? (isESModule ? parser.parseModule() : parser.parseProgram())
+ : parser.parse();
if (!success && !silent) {
const auto diagnosticMessages = parser.diagnosticMessages();
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
- qWarning("%s:%d : %s", qPrintable(filename), m.line, qPrintable(m.message));
+ qWarning().noquote() << QString::fromLatin1("%1:%2 : %3")
+ .arg(filename).arg(m.line).arg(m.message);
}
}
@@ -98,10 +103,12 @@ int main(int argv, char *argc[])
parser.addHelpOption();
parser.addVersionOption();
- QCommandLineOption silentOption(QStringList() << "s" << "silent", QLatin1String("Don't output syntax errors"));
+ QCommandLineOption silentOption(QStringList() << "s" << "silent",
+ QLatin1String("Don't output syntax errors"));
parser.addOption(silentOption);
- QCommandLineOption checkUnqualified(QStringList() << "U" << "check-unqualified", QLatin1String("Warn about unqualified identifiers"));
+ QCommandLineOption checkUnqualified(QStringList() << "U" << "check-unqualified",
+ QLatin1String("Warn about unqualified identifiers"));
parser.addOption(checkUnqualified);
QCommandLineOption qmltypesDirsOption(
@@ -111,7 +118,8 @@ int main(int argv, char *argc[])
QLatin1String("directory"));
parser.addOption(qmltypesDirsOption);
- parser.addPositionalArgument(QLatin1String("files"), QLatin1String("list of qml or js files to verify"));
+ parser.addPositionalArgument(QLatin1String("files"),
+ QLatin1String("list of qml or js files to verify"));
parser.process(app);
@@ -123,12 +131,14 @@ int main(int argv, char *argc[])
bool silent = parser.isSet(silentOption);
bool warnUnqualified = parser.isSet(checkUnqualified);
// use host qml import path as a sane default if nothing else has been provided
- QStringList qmltypeDirs = parser.isSet(qmltypesDirsOption) ? parser.values(qmltypesDirsOption)
-#ifndef QT_BOOTSTRAPPED
- : QStringList{QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath), QLatin1String(".")};
-#else
- : QStringList{QLatin1String(".")};
-#endif
+ QStringList qmltypeDirs = parser.isSet(qmltypesDirsOption)
+ ? parser.values(qmltypesDirsOption)
+# ifndef QT_BOOTSTRAPPED
+ : QStringList { QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath),
+ QLatin1String(".") };
+# else
+ : QStringList { QLatin1String(".") };
+# endif
#else
bool silent = false;
bool warnUnqualified = false;
diff --git a/tools/qmllint/metatypes.h b/tools/qmllint/metatypes.h
new file mode 100644
index 0000000000..24f8aa291e
--- /dev/null
+++ b/tools/qmllint/metatypes.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef METATYPES_H
+#define METATYPES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+
+class MetaEnum
+{
+ QString m_name;
+ QStringList m_keys;
+
+public:
+ MetaEnum() = default;
+ explicit MetaEnum(QString name) : m_name(std::move(name)) {}
+
+ bool isValid() const { return !m_name.isEmpty(); }
+
+ QString name() const { return m_name; }
+ void setName(const QString &name) { m_name = name; }
+
+ void addKey(const QString &key) { m_keys.append(key); }
+ QStringList keys() const { return m_keys; }
+};
+
+class MetaMethod
+{
+public:
+ enum Type {
+ Signal,
+ Slot,
+ Method
+ };
+
+ enum Access {
+ Private,
+ Protected,
+ Public
+ };
+
+ MetaMethod() = default;
+ explicit MetaMethod(QString name, QString returnType = QString())
+ : m_name(std::move(name))
+ , m_returnType(std::move(returnType))
+ , m_methodType(Method)
+ , m_methodAccess(Public)
+ {}
+
+ QString methodName() const { return m_name; }
+ void setMethodName(const QString &name) { m_name = name; }
+
+ void setReturnType(const QString &type) { m_returnType = type; }
+
+ QStringList parameterNames() const { return m_paramNames; }
+ QStringList parameterTypes() const { return m_paramTypes; }
+ void addParameter(const QString &name, const QString &type)
+ {
+ m_paramNames.append(name);
+ m_paramTypes.append(type);
+ }
+
+ int methodType() const { return m_methodType; }
+ void setMethodType(Type methodType) { m_methodType = methodType; }
+
+ Access access() const { return m_methodAccess; }
+
+ int revision() const { return m_revision; }
+ void setRevision(int r) { m_revision = r; }
+
+private:
+ QString m_name;
+ QString m_returnType;
+ QStringList m_paramNames;
+ QStringList m_paramTypes;
+ Type m_methodType = Signal;
+ Access m_methodAccess = Private;
+ int m_revision = 0;
+};
+
+class MetaProperty
+{
+ QString m_propertyName;
+ QString m_type;
+ bool m_isList;
+ bool m_isWritable;
+ bool m_isPointer;
+ int m_revision;
+
+public:
+ MetaProperty(QString name, QString type,
+ bool isList, bool isWritable, bool isPointer, int revision)
+ : m_propertyName(std::move(name))
+ , m_type(std::move(type))
+ , m_isList(isList)
+ , m_isWritable(isWritable)
+ , m_isPointer(isPointer)
+ , m_revision(revision)
+ {}
+
+ QString name() const { return m_propertyName; }
+ QString typeName() const { return m_type; }
+
+ bool isList() const { return m_isList; }
+ bool isWritable() const { return m_isWritable; }
+ bool isPointer() const { return m_isPointer; }
+ int revision() const { return m_revision; }
+};
+
+#endif // METATYPES_H
diff --git a/tools/qmllint/qcoloroutput.cpp b/tools/qmllint/qcoloroutput.cpp
index eb4c721663..84bd22c428 100644
--- a/tools/qmllint/qcoloroutput.cpp
+++ b/tools/qmllint/qcoloroutput.cpp
@@ -26,72 +26,76 @@
**
****************************************************************************/
-#include <QFile>
-#include <QHash>
-#include <QTextCodec>
+#include "qcoloroutput.h"
+
+#include <QtCore/qfile.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qtextcodec.h>
#ifndef Q_OS_WIN
#include <unistd.h>
#endif
-#include "qcoloroutput_p.h"
-
class ColorOutputPrivate
{
public:
- ColorOutputPrivate(bool silent) : currentColorID(-1), silent(silent)
-
+ ColorOutputPrivate(bool silent) : m_currentColorID(-1), m_silent(silent)
{
- /* - QIODevice::Unbuffered because we want it to appear when the user actually calls, performance
- * is considered of lower priority.
+ /* - QIODevice::Unbuffered because we want it to appear when the user actually calls,
+ * performance is considered of lower priority.
*/
m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered);
-
- coloringEnabled = isColoringPossible();
+ m_coloringEnabled = isColoringPossible();
}
- ColorOutput::ColorMapping colorMapping;
- int currentColorID;
- bool coloringEnabled;
- bool silent;
-
static const char *const foregrounds[];
static const char *const backgrounds[];
- inline void write(const QString &msg)
- {
- m_out.write(msg.toLocal8Bit());
- }
+ inline void write(const QString &msg) { m_out.write(msg.toLocal8Bit()); }
static QString escapeCode(const QString &in)
{
+ const ushort escapeChar = 0x1B;
QString result;
- result.append(QChar(0x1B));
+ result.append(QChar(escapeChar));
result.append(QLatin1Char('['));
result.append(in);
result.append(QLatin1Char('m'));
return result;
}
+ void insertColor(int id, ColorOutput::ColorCode code) { m_colorMapping.insert(id, code); }
+ ColorOutput::ColorCode color(int id) const { return m_colorMapping.value(id); }
+ bool containsColor(int id) const { return m_colorMapping.contains(id); }
+
+ bool isSilent() const { return m_silent; }
+ void setCurrentColorID(int colorId) { m_currentColorID = colorId; }
+
+ bool coloringEnabled() const { return m_coloringEnabled; }
+
private:
QFile m_out;
+ ColorOutput::ColorMapping m_colorMapping;
+ int m_currentColorID;
+ bool m_coloringEnabled;
+ bool m_silent;
/*!
Returns true if it's suitable to send colored output to \c stderr.
*/
inline bool isColoringPossible() const
{
-# if defined(Q_OS_WIN)
- /* Windows doesn't at all support ANSI escape codes, unless
- * the user install a "device driver". See the Wikipedia links in the
- * class documentation for details. */
- return false;
-# else
- /* We use QFile::handle() to get the file descriptor. It's a bit unsure
- * whether it's 2 on all platforms and in all cases, so hopefully this layer
- * of abstraction helps handle such cases. */
- return isatty(m_out.handle());
-# endif
+#if defined(Q_OS_WIN)
+ /* Windows doesn't at all support ANSI escape codes, unless
+ * the user install a "device driver". See the Wikipedia links in the
+ * class documentation for details. */
+ return false;
+#else
+ /* We use QFile::handle() to get the file descriptor. It's a bit unsure
+ * whether it's 2 on all platforms and in all cases, so hopefully this layer
+ * of abstraction helps handle such cases. */
+ return isatty(m_out.handle());
+#endif
}
};
@@ -128,7 +132,6 @@ const char *const ColorOutputPrivate::backgrounds[] =
/*!
\class ColorOutput
- \since 4.4
\nonreentrant
\brief Outputs colored messages to \c stderr.
\internal
@@ -215,40 +218,17 @@ const char *const ColorOutputPrivate::backgrounds[] =
*/
/*!
- Sets the color mapping to be \a cMapping.
-
- Negative values are disallowed.
-
- \sa colorMapping(), insertMapping()
- */
-void ColorOutput::setColorMapping(const ColorMapping &cMapping)
-{
- d->colorMapping = cMapping;
-}
-
-/*!
- Returns the color mappings in use.
-
- \sa setColorMapping(), insertMapping()
- */
-ColorOutput::ColorMapping ColorOutput::colorMapping() const
-{
- return d->colorMapping;
-}
-
-/*!
Constructs a ColorOutput instance, ready for use.
*/
-ColorOutput::ColorOutput(bool silent) : d(new ColorOutputPrivate(silent))
-{
-}
+ColorOutput::ColorOutput(bool silent) : d(new ColorOutputPrivate(silent)) {}
-ColorOutput::~ColorOutput() = default; // must be here so that QScopedPointer has access to the complete type
+// must be here so that QScopedPointer has access to the complete type
+ColorOutput::~ColorOutput() = default;
/*!
- Sends \a message to \c stderr, using the color looked up in colorMapping() using \a colorID.
+ Sends \a message to \c stderr, using the color looked up in the color mapping using \a colorID.
- If \a color isn't available in colorMapping(), result and behavior is undefined.
+ If \a color isn't available in the color mapping, result and behavior is undefined.
If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput
is initialized to not color at all.
@@ -259,7 +239,7 @@ ColorOutput::~ColorOutput() = default; // must be here so that QScopedPointer ha
*/
void ColorOutput::write(const QString &message, int colorID)
{
- if (!d->silent)
+ if (!d->isSilent())
d->write(colorify(message, colorID));
}
@@ -271,7 +251,7 @@ void ColorOutput::write(const QString &message, int colorID)
*/
void ColorOutput::writeUncolored(const QString &message)
{
- if (!d->silent)
+ if (!d->isSilent())
d->write(message + QLatin1Char('\n'));
}
@@ -285,61 +265,56 @@ void ColorOutput::writeUncolored(const QString &message)
*/
QString ColorOutput::colorify(const QString &message, int colorID) const
{
- Q_ASSERT_X(colorID == -1 || d->colorMapping.contains(colorID), Q_FUNC_INFO,
- qPrintable(QString::fromLatin1("There is no color registered by id %1").arg(colorID)));
- Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO, "It makes no sense to attempt to print an empty string.");
+ Q_ASSERT_X(colorID == -1 || d->containsColor(colorID), Q_FUNC_INFO,
+ qPrintable(QString::fromLatin1("There is no color registered by id %1")
+ .arg(colorID)));
+ Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO,
+ "It makes no sense to attempt to print an empty string.");
if (colorID != -1)
- d->currentColorID = colorID;
+ d->setCurrentColorID(colorID);
- if (d->coloringEnabled && colorID != -1)
- {
- const int color(d->colorMapping.value(colorID));
+ if (d->coloringEnabled() && colorID != -1) {
+ const int color = d->color(colorID);
/* If DefaultColor is set, we don't want to color it. */
if (color & DefaultColor)
return message;
- const int foregroundCode = (int(color) & ForegroundMask) >> ForegroundShift;
- const int backgroundCode = (int(color) & BackgroundMask) >> BackgroundShift;
+ const int foregroundCode = (color & ForegroundMask) >> ForegroundShift;
+ const int backgroundCode = (color & BackgroundMask) >> BackgroundShift;
QString finalMessage;
bool closureNeeded = false;
- if (foregroundCode)
- {
- finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
+ if (foregroundCode > 0) {
+ finalMessage.append(
+ ColorOutputPrivate::escapeCode(
+ QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
closureNeeded = true;
}
- if (backgroundCode)
- {
- finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
+ if (backgroundCode > 0) {
+ finalMessage.append(
+ ColorOutputPrivate::escapeCode(
+ QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
closureNeeded = true;
}
finalMessage.append(message);
if (closureNeeded)
- {
- finalMessage.append(QChar(0x1B));
- finalMessage.append(QLatin1String("[0m"));
- }
+ finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String("0")));
return finalMessage;
}
- else
- return message;
+
+ return message;
}
/*!
Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance.
-
- This is a convenience function for creating a ColorOutput::ColorMapping instance and
- calling setColorMapping().
-
- \sa colorMapping(), setColorMapping()
*/
-void ColorOutput::insertColorMapping(int colorID, const ColorCode colorCode)
+void ColorOutput::insertMapping(int colorID, const ColorCode colorCode)
{
- d->colorMapping.insert(colorID, colorCode);
+ d->insertColor(colorID, colorCode);
}
diff --git a/tools/qmllint/qcoloroutput_p.h b/tools/qmllint/qcoloroutput.h
index aefa765a87..92f4b47ff0 100644
--- a/tools/qmllint/qcoloroutput_p.h
+++ b/tools/qmllint/qcoloroutput.h
@@ -26,6 +26,9 @@
**
****************************************************************************/
+#ifndef QCOLOROUTPUT_H
+#define QCOLOROUTPUT_H
+
//
// W A R N I N G
// -------------
@@ -36,12 +39,8 @@
//
// We mean it.
-#ifndef QCOLOROUTPUT_P_H
-#define QCOLOROUTPUT_P_H
-
-#include <QtCore/QtGlobal>
-#include <QtCore/QHash>
-#include <QScopedPointer>
+#include <QtCore/qglobal.h>
+#include <QtCore/qscopedpointer.h>
class ColorOutputPrivate;
@@ -86,15 +85,13 @@ public:
DefaultColor = 1 << SpecialShift
};
- typedef QFlags<ColorCodeComponent> ColorCode;
- typedef QHash<int, ColorCode> ColorMapping;
+ using ColorCode = QFlags<ColorCodeComponent>;
+ using ColorMapping = QHash<int, ColorCode>;
ColorOutput(bool silent);
~ColorOutput();
- void setColorMapping(const ColorMapping &cMapping);
- ColorMapping colorMapping() const;
- void insertColorMapping(int colorID, const ColorCode colorCode);
+ void insertMapping(int colorID, ColorCode colorCode);
void writeUncolored(const QString &message);
void write(const QString &message, int color = -1);
@@ -102,9 +99,9 @@ public:
private:
QScopedPointer<ColorOutputPrivate> d;
- Q_DISABLE_COPY(ColorOutput)
+ Q_DISABLE_COPY_MOVE(ColorOutput)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(ColorOutput::ColorCode)
-#endif
+#endif // QCOLOROUTPUT_H
diff --git a/tools/qmllint/qmljstypedescriptionreader.h b/tools/qmllint/qmljstypedescriptionreader.h
deleted file mode 100644
index df215af8d2..0000000000
--- a/tools/qmllint/qmljstypedescriptionreader.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QMLJSTYPEDESCRIPTIONREADER_H
-#define QMLJSTYPEDESCRIPTIONREADER_H
-
-#include <private/qqmljsastfwd_p.h>
-#include "fakemetaobject.h"
-
-// for Q_DECLARE_TR_FUNCTIONS
-#include <QCoreApplication>
-
-QT_BEGIN_NAMESPACE
-class QIODevice;
-class QBuffer;
-
-namespace QQmlJS {
-
-class ModuleApiInfo
-{
-public:
- QString uri;
- LanguageUtils::ComponentVersion version;
- QString cppName;
-};
-
-
-class TypeDescriptionReader
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlJS::TypeDescriptionReader)
-
-public:
- explicit TypeDescriptionReader(const QString &fileName, const QString &data);
- ~TypeDescriptionReader();
-
- bool operator()(
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects,
- QList<ModuleApiInfo> *moduleApis,
- QStringList *dependencies);
- QString errorMessage() const;
- QString warningMessage() const;
-
-private:
- void readDocument(AST::UiProgram *ast);
- void readModule(AST::UiObjectDefinition *ast);
- void readDependencies(AST::UiScriptBinding *ast);
- void readComponent(AST::UiObjectDefinition *ast);
- void readModuleApi(AST::UiObjectDefinition *ast);
- void readSignalOrMethod(AST::UiObjectDefinition *ast, bool isMethod, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readProperty(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readEnum(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readParameter(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaMethod *fmm);
-
- QString readStringBinding(AST::UiScriptBinding *ast);
- bool readBoolBinding(AST::UiScriptBinding *ast);
- double readNumericBinding(AST::UiScriptBinding *ast);
- LanguageUtils::ComponentVersion readNumericVersionBinding(AST::UiScriptBinding *ast);
- int readIntBinding(AST::UiScriptBinding *ast);
- void readExports(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readMetaObjectRevisions(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
- void readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme);
-
- void addError(const AST::SourceLocation &loc, const QString &message);
- void addWarning(const AST::SourceLocation &loc, const QString &message);
-
- QString _fileName;
- QString _source;
- QString _errorMessage;
- QString _warningMessage;
- QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects;
- QList<ModuleApiInfo> *_moduleApis = nullptr;
- QStringList *_dependencies = nullptr;
-};
-
-} // namespace QQmlJS
-QT_END_NAMESPACE
-
-#endif // QMLJSTYPEDESCRIPTIONREADER_H
diff --git a/tools/qmllint/qmllint.pro b/tools/qmllint/qmllint.pro
index 76363a7cd8..2631768b81 100644
--- a/tools/qmllint/qmllint.pro
+++ b/tools/qmllint/qmllint.pro
@@ -4,11 +4,10 @@ QT = core qmldevtools-private
SOURCES += main.cpp \
componentversion.cpp \
- fakemetaobject.cpp \
findunqualified.cpp \
- qmljstypedescriptionreader.cpp \
qcoloroutput.cpp \
- scopetree.cpp
+ scopetree.cpp \
+ typedescriptionreader.cpp
QMAKE_TARGET_DESCRIPTION = QML Syntax Verifier
@@ -16,8 +15,8 @@ load(qt_tool)
HEADERS += \
componentversion.h \
- fakemetaobject.h \
findunqualified.h \
- qmljstypedescriptionreader.h \
- qcoloroutput_p.h \
- scopetree.h
+ metatypes.h \
+ qcoloroutput.h \
+ scopetree.h \
+ typedescriptionreader.h
diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp
index 1e873cca8f..7e9be92673 100644
--- a/tools/qmllint/scopetree.cpp
+++ b/tools/qmllint/scopetree.cpp
@@ -27,28 +27,27 @@
****************************************************************************/
#include "scopetree.h"
+#include "qcoloroutput.h"
-#include "qcoloroutput_p.h"
+#include <QtCore/qqueue.h>
#include <algorithm>
-#include <QQueue>
-
ScopeTree::ScopeTree(ScopeType type, QString name, ScopeTree *parentScope)
- : m_parentScope(parentScope), m_name(name), m_scopeType(type) {}
+ : m_parentScope(parentScope), m_name(std::move(name)), m_scopeType(type) {}
-ScopeTree *ScopeTree::createNewChildScope(ScopeType type, QString name) {
- Q_ASSERT(type != ScopeType::QMLScope|| !m_parentScope || m_parentScope->m_scopeType == ScopeType::QMLScope || m_parentScope->m_name == "global");
- auto childScope = new ScopeTree{type, name, this};
+ScopeTree *ScopeTree::createNewChildScope(ScopeType type, QString name)
+{
+ Q_ASSERT(type != ScopeType::QMLScope
+ || !m_parentScope
+ || m_parentScope->m_scopeType == ScopeType::QMLScope
+ || m_parentScope->m_name == "global");
+ auto childScope = new ScopeTree{type, std::move(name), this};
m_childScopes.push_back(childScope);
return childScope;
}
-ScopeTree *ScopeTree::parentScope() {
- return m_parentScope;
-}
-
-void ScopeTree::insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope)
+void ScopeTree::insertJSIdentifier(const QString &id, QQmlJS::AST::VariableScope scope)
{
Q_ASSERT(m_scopeType != ScopeType::QMLScope);
if (scope == QQmlJS::AST::VariableScope::Var) {
@@ -56,29 +55,25 @@ void ScopeTree::insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope)
while (targetScope->scopeType() != ScopeType::JSFunctionScope) {
targetScope = targetScope->m_parentScope;
}
- targetScope->m_currentScopeJSIdentifiers.insert(id);
+ targetScope->m_jsIdentifiers.insert(id);
} else {
- m_currentScopeJSIdentifiers.insert(id);
+ m_jsIdentifiers.insert(id);
}
}
-void ScopeTree::insertQMLIdentifier(QString id)
-{
- Q_ASSERT(m_scopeType == ScopeType::QMLScope);
- m_currentScopeQMLIdentifiers.insert(id);
-}
-
-void ScopeTree::insertSignalIdentifier(QString id, LanguageUtils::FakeMetaMethod method, QQmlJS::AST::SourceLocation loc, bool hasMultilineHandlerBody)
+void ScopeTree::insertSignalIdentifier(const QString &id, const MetaMethod &method,
+ const QQmlJS::AST::SourceLocation &loc,
+ bool hasMultilineHandlerBody)
{
Q_ASSERT(m_scopeType == ScopeType::QMLScope);
m_injectedSignalIdentifiers.insert(id, {method, loc, hasMultilineHandlerBody});
}
-void ScopeTree::insertPropertyIdentifier(QString id)
+void ScopeTree::insertPropertyIdentifier(const MetaProperty &property)
{
- this->insertQMLIdentifier(id);
- LanguageUtils::FakeMetaMethod method( id + QLatin1String("Changed"), "void");
- this->addMethod(method);
+ addProperty(property);
+ MetaMethod method(property.name() + QLatin1String("Changed"), "void");
+ addMethod(method);
}
void ScopeTree::addUnmatchedSignalHandler(const QString &handler,
@@ -92,52 +87,62 @@ bool ScopeTree::isIdInCurrentScope(const QString &id) const
return isIdInCurrentQMlScopes(id) || isIdInCurrentJSScopes(id);
}
-void ScopeTree::addIdToAccssedIfNotInParentScopes(const QPair<QString, QQmlJS::AST::SourceLocation> &id_loc_pair, const QSet<QString>& unknownImports) {
+void ScopeTree::addIdToAccssedIfNotInParentScopes(
+ const QPair<QString, QQmlJS::AST::SourceLocation> &idLocationPair,
+ const QSet<QString> &unknownImports)
+{
// also do not add id if it is parent
// parent is almost always defined valid in QML, and if we could not find a definition for the current QML component
// not skipping "parent" will lead to many false positives
// Moreover, if the top level item is Item or inherits from it, it will have a parent property to which we would point the user
// which makes for a very nonsensical warning
- auto qmlScope = getCurrentQMLScope();
- if (!isIdInCurrentScope(id_loc_pair.first) && !(id_loc_pair.first == QLatin1String("parent") && qmlScope && unknownImports.contains(qmlScope->name()))) {
- m_accessedIdentifiers.push_back(id_loc_pair);
+ const auto *qmlScope = currentQMLScope();
+ if (!isIdInCurrentScope(idLocationPair.first)
+ && !(idLocationPair.first == QLatin1String("parent")
+ && qmlScope && unknownImports.contains(qmlScope->name()))) {
+ m_accessedIdentifiers.push_back(idLocationPair);
}
}
bool ScopeTree::isVisualRootScope() const
{
- return m_parentScope && m_parentScope->m_parentScope && m_parentScope->m_parentScope->m_parentScope == nullptr;
+ return m_parentScope && m_parentScope->m_parentScope
+ && m_parentScope->m_parentScope->m_parentScope == nullptr;
}
-QString ScopeTree::name() const
+class IssueLocationWithContext
{
- return m_name;
-}
-
-struct IssueLocationWithContext
-{
- IssueLocationWithContext(const QString& code, QQmlJS::AST::SourceLocation location) {
+public:
+ IssueLocationWithContext(const QString &code, const QQmlJS::AST::SourceLocation &location) {
int before = std::max(0,code.lastIndexOf('\n', location.offset));
- beforeText = code.midRef(before+1, location.offset - (before+1) );
- issueText = code.midRef(location.offset, location.length);
- int after = code.indexOf('\n', location.offset + location.length);
- afterText = code.midRef(location.offset+location.length, after - (location.offset+location.length));
+ m_beforeText = code.midRef(before + 1, int(location.offset - (before + 1)));
+ m_issueText = code.midRef(location.offset, location.length);
+ int after = code.indexOf('\n', int(location.offset + location.length));
+ m_afterText = code.midRef(int(location.offset + location.length),
+ int(after - (location.offset+location.length)));
}
- QStringRef beforeText;
- QStringRef issueText;
- QStringRef afterText;
+ QStringRef beforeText() const { return m_beforeText; }
+ QStringRef issueText() const { return m_issueText; }
+ QStringRef afterText() const { return m_afterText; }
+
+private:
+ QStringRef m_beforeText;
+ QStringRef m_issueText;
+ QStringRef m_afterText;
};
-bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> &qmlIDs, const ScopeTree *root, const QString& rootId, ColorOutput& colorOut) const
+bool ScopeTree::recheckIdentifiers(
+ const QString &code, const QHash<QString, ScopeTree::ConstPtr> &qmlIDs,
+ const ScopeTree *root, const QString &rootId, ColorOutput &colorOut) const
{
bool noUnqualifiedIdentifier = true;
// revisit all scopes
- QQueue<const ScopeTree*> workQueue;
+ QQueue<const ScopeTree *> workQueue;
workQueue.enqueue(this);
while (!workQueue.empty()) {
- const ScopeTree* currentScope = workQueue.dequeue();
+ const ScopeTree *currentScope = workQueue.dequeue();
for (const auto &handler : currentScope->m_unmatchedSignalHandlers) {
colorOut.write("Warning: ", Warning);
colorOut.write(QString::fromLatin1(
@@ -147,7 +152,7 @@ bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, Lan
printContext(colorOut, code, handler.second);
}
- for (auto idLocationPair : currentScope->m_accessedIdentifiers) {
+ for (const auto &idLocationPair : qAsConst(currentScope->m_accessedIdentifiers)) {
if (qmlIDs.contains(idLocationPair.first))
continue;
if (currentScope->isIdInCurrentScope(idLocationPair.first)) {
@@ -156,17 +161,17 @@ bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, Lan
noUnqualifiedIdentifier = false;
colorOut.write("Warning: ", Warning);
auto location = idLocationPair.second;
- colorOut.write(QString::asprintf("unqualified access at %d:%d\n", location.startLine,
- location.startColumn), Normal);
+ colorOut.write(QString::fromLatin1("unqualified access at %1:%2\n")
+ .arg(location.startLine).arg(location.startColumn),
+ Normal);
printContext(colorOut, code, location);
// root(JS) --> program(qml) --> (first element)
- if (root->m_childScopes[0]->m_childScopes[0]->m_currentScopeQMLIdentifiers.contains(idLocationPair.first)) {
- ScopeTree *parentScope = currentScope->m_parentScope;
- while (parentScope && parentScope->scopeType() != ScopeType::QMLScope) {
- parentScope = parentScope->m_parentScope;
- }
+ const auto firstElement = root->m_childScopes[0]->m_childScopes[0];
+ if (firstElement->m_properties.contains(idLocationPair.first)
+ || firstElement->m_methods.contains(idLocationPair.first)
+ || firstElement->m_enums.contains(idLocationPair.first)) {
colorOut.write("Note: ", Info);
colorOut.write( idLocationPair.first + QLatin1String(" is a meber of the root element\n"), Normal );
colorOut.write(QLatin1String(" You can qualify the access with its id to avoid this warning:\n"), Normal);
@@ -175,92 +180,87 @@ bool ScopeTree::recheckIdentifiers(const QString& code, const QHash<QString, Lan
colorOut.write(("You first have to give the root element an id\n"));
}
IssueLocationWithContext issueLocationWithContext {code, location};
- colorOut.write(issueLocationWithContext.beforeText.toString(), Normal);
+ colorOut.write(issueLocationWithContext.beforeText().toString(), Normal);
colorOut.write(rootId + QLatin1Char('.'), Hint);
- colorOut.write(issueLocationWithContext.issueText.toString(), Normal);
- colorOut.write(issueLocationWithContext.afterText + QLatin1Char('\n'), Normal);
+ colorOut.write(issueLocationWithContext.issueText().toString(), Normal);
+ colorOut.write(issueLocationWithContext.afterText() + QLatin1Char('\n'), Normal);
} else if (currentScope->isIdInjectedFromSignal(idLocationPair.first)) {
- auto qmlScope = currentScope->getCurrentQMLScope();
- auto methodUsages = qmlScope->m_injectedSignalIdentifiers.values(idLocationPair.first);
+ auto methodUsages = currentScope->currentQMLScope()->m_injectedSignalIdentifiers
+ .values(idLocationPair.first);
auto location = idLocationPair.second;
// sort the list of signal handlers by their occurrence in the source code
// then, we select the first one whose location is after the unqualified id
// and go one step backwards to get the one which we actually need
- std::sort(methodUsages.begin(), methodUsages.end(), [](const MethodUsage m1, const MethodUsage m2) {
- return m1.loc.startLine < m2.loc.startLine || (m1.loc.startLine == m2.loc.startLine && m1.loc.startColumn < m2.loc.startColumn);
+ std::sort(methodUsages.begin(), methodUsages.end(),
+ [](const MethodUsage &m1, const MethodUsage &m2) {
+ return m1.loc.startLine < m2.loc.startLine
+ || (m1.loc.startLine == m2.loc.startLine
+ && m1.loc.startColumn < m2.loc.startColumn);
});
- auto oneBehindIt = std::find_if(methodUsages.begin(), methodUsages.end(), [&location](MethodUsage methodUsage) {
- return location.startLine < methodUsage.loc.startLine || (location.startLine == methodUsage.loc.startLine && location.startColumn < methodUsage.loc.startColumn);
+ auto oneBehindIt = std::find_if(methodUsages.begin(), methodUsages.end(),
+ [&location](const MethodUsage &methodUsage) {
+ return location.startLine < methodUsage.loc.startLine
+ || (location.startLine == methodUsage.loc.startLine
+ && location.startColumn < methodUsage.loc.startColumn);
});
auto methodUsage = *(--oneBehindIt);
colorOut.write("Note:", Info);
- colorOut.write(idLocationPair.first + QString::asprintf(" is accessible in this scope because you are handling a signal at %d:%d\n", methodUsage.loc.startLine, methodUsage.loc.startColumn), Normal);
+ colorOut.write(
+ idLocationPair.first + QString::fromLatin1(
+ " is accessible in this scope because "
+ "you are handling a signal at %1:%2\n")
+ .arg(methodUsage.loc.startLine).arg(methodUsage.loc.startColumn),
+ Normal);
colorOut.write("Consider using a function instead\n", Normal);
IssueLocationWithContext context {code, methodUsage.loc};
- colorOut.write(context.beforeText + QLatin1Char(' '));
+ colorOut.write(context.beforeText() + QLatin1Char(' '));
colorOut.write(methodUsage.hasMultilineHandlerBody ? "function(" : "(", Hint);
const auto parameters = methodUsage.method.parameterNames();
for (int numParams = parameters.size(); numParams > 0; --numParams) {
colorOut.write(parameters.at(parameters.size() - numParams), Hint);
- if (numParams > 1) {
+ if (numParams > 1)
colorOut.write(", ", Hint);
- }
}
colorOut.write(methodUsage.hasMultilineHandlerBody ? ")" : ") => ", Hint);
colorOut.write(" {...", Normal);
}
colorOut.write("\n\n\n", Normal);
}
- for (auto const& childScope: currentScope->m_childScopes) {
+ for (auto const& childScope: currentScope->m_childScopes)
workQueue.enqueue(childScope);
- }
}
return noUnqualifiedIdentifier;
}
-QMap<QString, LanguageUtils::FakeMetaMethod>const &ScopeTree::methods() const
+bool ScopeTree::isIdInCurrentQMlScopes(const QString &id) const
{
- return m_methods;
+ const auto *qmlScope = currentQMLScope();
+ return qmlScope->m_properties.contains(id)
+ || qmlScope->m_methods.contains(id)
+ || qmlScope->m_enums.contains(id);
}
-bool ScopeTree::isIdInCurrentQMlScopes(QString id) const
-{
- auto qmlScope = getCurrentQMLScope();
- return qmlScope->m_currentScopeQMLIdentifiers.contains(id) || qmlScope->m_methods.contains(id);
-}
-
-bool ScopeTree::isIdInCurrentJSScopes(QString id) const
+bool ScopeTree::isIdInCurrentJSScopes(const QString &id) const
{
auto jsScope = this;
while (jsScope) {
- if (jsScope->m_scopeType != ScopeType::QMLScope && jsScope->m_currentScopeJSIdentifiers.contains(id))
+ if (jsScope->m_scopeType != ScopeType::QMLScope && jsScope->m_jsIdentifiers.contains(id))
return true;
jsScope = jsScope->m_parentScope;
}
return false;
}
-bool ScopeTree::isIdInjectedFromSignal(QString id) const
-{
- auto qmlScope = getCurrentQMLScope();
- return qmlScope->m_injectedSignalIdentifiers.contains(id);
-}
-
-const ScopeTree *ScopeTree::getCurrentQMLScope() const
+bool ScopeTree::isIdInjectedFromSignal(const QString &id) const
{
- auto qmlScope = this;
- while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope) {
- qmlScope = qmlScope->m_parentScope;
- }
- return qmlScope;
+ return currentQMLScope()->m_injectedSignalIdentifiers.contains(id);
}
-ScopeTree *ScopeTree::getCurrentQMLScope()
+const ScopeTree *ScopeTree::currentQMLScope() const
{
auto qmlScope = this;
- while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope) {
+ while (qmlScope && qmlScope->m_scopeType != ScopeType::QMLScope)
qmlScope = qmlScope->m_parentScope;
- }
return qmlScope;
}
@@ -268,30 +268,37 @@ void ScopeTree::printContext(ColorOutput &colorOut, const QString &code,
const QQmlJS::AST::SourceLocation &location) const
{
IssueLocationWithContext issueLocationWithContext {code, location};
- colorOut.write(issueLocationWithContext.beforeText.toString(), Normal);
- colorOut.write(issueLocationWithContext.issueText.toString(), Error);
- colorOut.write(issueLocationWithContext.afterText.toString() + QLatin1Char('\n'), Normal);
- int tabCount = issueLocationWithContext.beforeText.count(QLatin1Char('\t'));
- colorOut.write(QString(" ").repeated(issueLocationWithContext.beforeText.length() - tabCount)
+ colorOut.write(issueLocationWithContext.beforeText().toString(), Normal);
+ colorOut.write(issueLocationWithContext.issueText().toString(), Error);
+ colorOut.write(issueLocationWithContext.afterText().toString() + QLatin1Char('\n'), Normal);
+ int tabCount = issueLocationWithContext.beforeText().count(QLatin1Char('\t'));
+ colorOut.write(QString(" ").repeated(issueLocationWithContext.beforeText().length() - tabCount)
+ QString("\t").repeated(tabCount)
+ QString("^").repeated(location.length)
+ QLatin1Char('\n'), Normal);
}
-ScopeType ScopeTree::scopeType() {return m_scopeType;}
+void ScopeTree::addExport(const QString &name, const QString &package,
+ const ComponentVersion &version)
+{
+ m_exports.append(Export(package, name, version, 0));
+}
-void ScopeTree::addMethod(LanguageUtils::FakeMetaMethod method)
+void ScopeTree::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
{
- m_methods.insert(method.methodName(), method);
+ m_exports[exportIndex].setMetaObjectRevision(metaObjectRevision);
}
-void ScopeTree::addMethodsFromMetaObject(LanguageUtils::FakeMetaObject::ConstPtr metaObject)
+ScopeTree::Export::Export(QString package, QString type, const ComponentVersion &version,
+ int metaObjectRevision) :
+ m_package(std::move(package)),
+ m_type(std::move(type)),
+ m_version(version),
+ m_metaObjectRevision(metaObjectRevision)
{
- if (metaObject) {
- auto methodCount = metaObject->methodCount();
- for (auto i = 0; i < methodCount; ++i) {
- auto method = metaObject->method(i);
- this->addMethod(method);
- }
- }
+}
+
+bool ScopeTree::Export::isValid() const
+{
+ return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
}
diff --git a/tools/qmllint/scopetree.h b/tools/qmllint/scopetree.h
index 52cdc45e96..4b0d4a9539 100644
--- a/tools/qmllint/scopetree.h
+++ b/tools/qmllint/scopetree.h
@@ -29,15 +29,28 @@
#ifndef SCOPETREE_H
#define SCOPETREE_H
-#include "fakemetaobject.h"
-#include "private/qqmljsast_p.h"
-#include "private/qqmljssourcelocation_p.h"
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
-#include <QSet>
-#include <QString>
-#include <QMap>
+#include "metatypes.h"
+#include "componentversion.h"
-enum MessageColors{
+#include <QtQml/private/qqmljsast_p.h>
+#include <QtQml/private/qqmljssourcelocation_p.h>
+
+#include <QtCore/qset.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qstring.h>
+
+enum MessageColors
+{
Error,
Warning,
Info,
@@ -54,58 +67,137 @@ enum class ScopeType
struct MethodUsage
{
- LanguageUtils::FakeMetaMethod method;
+ MetaMethod method;
QQmlJS::AST::SourceLocation loc;
bool hasMultilineHandlerBody;
};
class ColorOutput;
-
-class ScopeTree {
+class ScopeTree
+{
+ Q_DISABLE_COPY_MOVE(ScopeTree)
public:
- ScopeTree(ScopeType type, QString name="<none given>", ScopeTree* parentScope=nullptr);
- ~ScopeTree() {qDeleteAll(m_childScopes);}
+ using Ptr = QSharedPointer<ScopeTree>;
+ using ConstPtr = QSharedPointer<const ScopeTree>;
+
+ class Export {
+ public:
+ Export() = default;
+ Export(QString package, QString type, const ComponentVersion &version,
+ int metaObjectRevision);
+
+ bool isValid() const;
+
+ int metaObjectRevision() const { return m_metaObjectRevision; }
+ void setMetaObjectRevision(int metaObjectRevision)
+ {
+ m_metaObjectRevision = metaObjectRevision;
+ }
- ScopeTree* createNewChildScope(ScopeType type, QString name);
- ScopeTree* parentScope();
+ QString package() const { return m_package; }
+ QString type() const { return m_type; }
- void insertJSIdentifier(QString id, QQmlJS::AST::VariableScope scope);
- void insertQMLIdentifier(QString id);
- void insertSignalIdentifier(QString id, LanguageUtils::FakeMetaMethod method, QQmlJS::AST::SourceLocation loc, bool hasMultilineHandlerBody);
- void insertPropertyIdentifier(QString id); // inserts property as qml identifier as well as the corresponding
+ private:
+ QString m_package;
+ QString m_type;
+ ComponentVersion m_version;
+ int m_metaObjectRevision = 0;
+ };
+
+ ScopeTree(ScopeType type, QString name="<none given>", ScopeTree *parentScope=nullptr);
+ ~ScopeTree() { qDeleteAll(m_childScopes); }
+
+ ScopeTree *createNewChildScope(ScopeType type, QString name);
+ ScopeTree *parentScope() { return m_parentScope; }
+
+ void insertJSIdentifier(const QString &id, QQmlJS::AST::VariableScope scope);
+ void insertSignalIdentifier(const QString &id, const MetaMethod &method,
+ const QQmlJS::AST::SourceLocation &loc, bool hasMultilineHandlerBody);
+ // inserts property as qml identifier as well as the corresponding
+ void insertPropertyIdentifier(const MetaProperty &prop);
void addUnmatchedSignalHandler(const QString &handler,
const QQmlJS::AST::SourceLocation &location);
- bool isIdInCurrentScope(QString const &id) const;
- void addIdToAccssedIfNotInParentScopes(QPair<QString, QQmlJS::AST::SourceLocation> const& id_loc_pair, const QSet<QString>& unknownImports);
+ bool isIdInCurrentScope(const QString &id) const;
+ void addIdToAccssedIfNotInParentScopes(
+ const QPair<QString, QQmlJS::AST::SourceLocation> &idLocationPair,
+ const QSet<QString> &unknownImports);
bool isVisualRootScope() const;
- QString name() const;
+ QString name() const { return m_name; }
+
+ bool recheckIdentifiers(
+ const QString &code, const QHash<QString, ScopeTree::ConstPtr> &qmlIDs,
+ const ScopeTree *root, const QString &rootId, ColorOutput &colorOut) const;
+
+ ScopeType scopeType() const { return m_scopeType; }
+
+ void addMethods(const QHash<QString, MetaMethod> &methods) { m_methods.unite(methods); }
+ void addMethod(const MetaMethod &method) { m_methods.insert(method.methodName(), method); }
+ QHash<QString, MetaMethod> methods() const { return m_methods; }
+
+ void addEnum(const MetaEnum &fakeEnum) { m_enums.insert(fakeEnum.name(), fakeEnum); }
+ QHash<QString, MetaEnum> enums() const { return m_enums; }
- bool recheckIdentifiers(const QString &code, const QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr>& qmlIDs, const ScopeTree *root, const QString& rootId, ColorOutput &colorOut) const;
- ScopeType scopeType();
- void addMethod(LanguageUtils::FakeMetaMethod);
- void addMethodsFromMetaObject(LanguageUtils::FakeMetaObject::ConstPtr metaObject);
- QMap<QString, LanguageUtils::FakeMetaMethod>const & methods() const;
+ QString className() const { return m_className; }
+ void setClassName(const QString &name) { m_className = name; }
+
+ void addExport(const QString &name, const QString &package, const ComponentVersion &version);
+ void setExportMetaObjectRevision(int exportIndex, int metaObjectRevision);
+ QList<Export> exports() const { return m_exports; }
+
+ void setSuperclassName(const QString &superclass) { m_superName = superclass; }
+ QString superclassName() const { return m_superName; }
+
+ void addProperty(const MetaProperty &prop) { m_properties.insert(prop.name(), prop); }
+ QHash<QString, MetaProperty> properties() const { return m_properties; }
+
+ QString defaultPropertyName() const { return m_defaultPropertyName; }
+ void setDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; }
+
+ QString attachedTypeName() const { return m_attachedTypeName; }
+ void setAttachedTypeName(const QString &name) { m_attachedTypeName = name; }
+
+ bool isSingleton() const { return m_isSingleton; }
+ bool isCreatable() const { return m_isCreatable; }
+ bool isComposite() const { return m_isComposite; }
+ void setIsSingleton(bool value) { m_isSingleton = value; }
+ void setIsCreatable(bool value) { m_isCreatable = value; }
+ void setIsComposite(bool value) { m_isSingleton = value; }
private:
- QSet<QString> m_currentScopeJSIdentifiers;
- QSet<QString> m_currentScopeQMLIdentifiers;
+ QSet<QString> m_jsIdentifiers;
QMultiHash<QString, MethodUsage> m_injectedSignalIdentifiers;
- QMap<QString, LanguageUtils::FakeMetaMethod> m_methods;
+
+ QHash<QString, MetaMethod> m_methods;
+ QHash<QString, MetaProperty> m_properties;
+ QHash<QString, MetaEnum> m_enums;
+
QVector<QPair<QString, QQmlJS::AST::SourceLocation>> m_accessedIdentifiers;
- QVector<ScopeTree*> m_childScopes;
- ScopeTree *m_parentScope;
- QString m_name;
- ScopeType m_scopeType;
QVector<QPair<QString, QQmlJS::AST::SourceLocation>> m_unmatchedSignalHandlers;
- bool isIdInCurrentQMlScopes(QString id) const;
- bool isIdInCurrentJSScopes(QString id) const;
- bool isIdInjectedFromSignal(QString id) const;
- const ScopeTree* getCurrentQMLScope() const;
- ScopeTree* getCurrentQMLScope();
- void printContext(ColorOutput& colorOut, const QString &code,
+ QVector<ScopeTree *> m_childScopes;
+ ScopeTree *m_parentScope = nullptr;
+
+ QString m_name;
+ QString m_className;
+ QString m_superName;
+
+ ScopeType m_scopeType = ScopeType::QMLScope;
+ QList<Export> m_exports;
+
+ QString m_defaultPropertyName;
+ QString m_attachedTypeName;
+ bool m_isSingleton = false;
+ bool m_isCreatable = true;
+ bool m_isComposite = false;
+
+ bool isIdInCurrentQMlScopes(const QString &id) const;
+ bool isIdInCurrentJSScopes(const QString &id) const;
+ bool isIdInjectedFromSignal(const QString &id) const;
+ const ScopeTree *currentQMLScope() const;
+ void printContext(ColorOutput &colorOut, const QString &code,
const QQmlJS::AST::SourceLocation &location) const;
};
+
#endif // SCOPETREE_H
diff --git a/tools/qmllint/qmljstypedescriptionreader.cpp b/tools/qmllint/typedescriptionreader.cpp
index b8aecdddb1..4f0cc88800 100644
--- a/tools/qmllint/qmljstypedescriptionreader.cpp
+++ b/tools/qmllint/typedescriptionreader.cpp
@@ -26,25 +26,18 @@
**
****************************************************************************/
-#include "qmljstypedescriptionreader.h"
+#include "typedescriptionreader.h"
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsengine_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
-#include <QDir>
-
-#define QTC_ASSERT_STRINGIFY_HELPER(x) #x
-#define QTC_ASSERT_STRINGIFY(x) QTC_ASSERT_STRINGIFY_HELPER(x)
-#define QTC_ASSERT_STRING(cond) qDebug() << (\
- "\"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__))
-#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0)
+#include <QtCore/qdir.h>
using namespace QQmlJS;
using namespace QQmlJS::AST;
-using namespace LanguageUtils;
-QString toString(const AST::UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
+QString toString(const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
{
QString result;
@@ -58,17 +51,8 @@ QString toString(const AST::UiQualifiedId *qualifiedId, QChar delimiter = QLatin
return result;
}
-TypeDescriptionReader::TypeDescriptionReader(const QString &fileName, const QString &data)
- : _fileName (fileName), _source(data), _objects(0)
-{
-}
-
-TypeDescriptionReader::~TypeDescriptionReader()
-{
-}
-
bool TypeDescriptionReader::operator()(
- QHash<QString, FakeMetaObject::ConstPtr> *objects,
+ QHash<QString, ScopeTree::ConstPtr> *objects,
QList<ModuleApiInfo> *moduleApis,
QStringList *dependencies)
{
@@ -77,32 +61,22 @@ bool TypeDescriptionReader::operator()(
Lexer lexer(&engine);
Parser parser(&engine);
- lexer.setCode(_source, /*line = */ 1, /*qmlMode = */true);
+ lexer.setCode(m_source, /*lineno = */ 1, /*qmlMode = */true);
if (!parser.parse()) {
- _errorMessage = QString::fromLatin1("%1:%2: %3").arg(
+ m_errorMessage = QString::fromLatin1("%1:%2: %3").arg(
QString::number(parser.errorLineNumber()),
QString::number(parser.errorColumnNumber()),
parser.errorMessage());
return false;
}
- _objects = objects;
- _moduleApis = moduleApis;
- _dependencies = dependencies;
+ m_objects = objects;
+ m_moduleApis = moduleApis;
+ m_dependencies = dependencies;
readDocument(parser.ast());
- return _errorMessage.isEmpty();
-}
-
-QString TypeDescriptionReader::errorMessage() const
-{
- return _errorMessage;
-}
-
-QString TypeDescriptionReader::warningMessage() const
-{
- return _warningMessage;
+ return m_errorMessage.isEmpty();
}
void TypeDescriptionReader::readDocument(UiProgram *ast)
@@ -112,12 +86,12 @@ void TypeDescriptionReader::readDocument(UiProgram *ast)
return;
}
- if (!ast->headers || ast->headers->next || !AST::cast<AST::UiImport *>(ast->headers->headerItem)) {
+ if (!ast->headers || ast->headers->next || !cast<UiImport *>(ast->headers->headerItem)) {
addError(SourceLocation(), tr("Expected a single import."));
return;
}
- UiImport *import = AST::cast<AST::UiImport *>(ast->headers->headerItem);
+ auto *import = cast<UiImport *>(ast->headers->headerItem);
if (toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
addError(import->importToken, tr("Expected import of QtQuick.tooling."));
return;
@@ -129,7 +103,8 @@ void TypeDescriptionReader::readDocument(UiProgram *ast)
}
if (import->version->majorVersion != 1) {
- addError(import->version->firstSourceLocation(), tr("Major version different from 1 not supported."));
+ addError(import->version->firstSourceLocation(),
+ tr("Major version different from 1 not supported."));
return;
}
@@ -138,7 +113,7 @@ void TypeDescriptionReader::readDocument(UiProgram *ast)
return;
}
- UiObjectDefinition *module = AST::cast<UiObjectDefinition *>(ast->members->member);
+ auto *module = cast<UiObjectDefinition *>(ast->members->member);
if (!module) {
addError(SourceLocation(), tr("Expected document to contain a single object definition."));
return;
@@ -156,9 +131,9 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
{
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
+ auto *component = cast<UiObjectDefinition *>(member);
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (script && (toString(script->qualifiedId) == QStringLiteral("dependencies"))) {
readDependencies(script);
continue;
@@ -168,7 +143,8 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
if (component)
typeName = toString(component->qualifiedTypeNameId);
- if (!component || (typeName != QLatin1String("Component") && typeName != QLatin1String("ModuleApi"))) {
+ if (!component || (typeName != QLatin1String("Component")
+ && typeName != QLatin1String("ModuleApi"))) {
continue;
}
@@ -181,8 +157,8 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &message)
{
- _errorMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
- QDir::toNativeSeparators(_fileName),
+ m_errorMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
+ QDir::toNativeSeparators(m_fileName),
QString::number(loc.startLine),
QString::number(loc.startColumn),
message);
@@ -190,8 +166,8 @@ void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &m
void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString &message)
{
- _warningMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
- QDir::toNativeSeparators(_fileName),
+ m_warningMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
+ QDir::toNativeSeparators(m_fileName),
QString::number(loc.startLine),
QString::number(loc.startColumn),
message);
@@ -199,83 +175,82 @@ void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString
void TypeDescriptionReader::readDependencies(UiScriptBinding *ast)
{
- ExpressionStatement *stmt = AST::cast<ExpressionStatement*>(ast->statement);
+ auto *stmt = cast<ExpressionStatement*>(ast->statement);
if (!stmt) {
addError(ast->statement->firstSourceLocation(), tr("Expected dependency definitions"));
return;
}
- ArrayPattern *exp = AST::cast<ArrayPattern *>(stmt->expression);
+ auto *exp = cast<ArrayPattern *>(stmt->expression);
if (!exp) {
addError(stmt->expression->firstSourceLocation(), tr("Expected dependency definitions"));
return;
}
for (PatternElementList *l = exp->elements; l; l = l->next) {
- //StringLiteral *str = AST::cast<StringLiteral *>(l->element->initializer);
- StringLiteral *str = AST::cast<StringLiteral *>(l->element->initializer);
- *_dependencies << str->value.toString();
+ auto *str = cast<StringLiteral *>(l->element->initializer);
+ *m_dependencies << str->value.toString();
}
}
void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
{
- FakeMetaObject::Ptr fmo(new FakeMetaObject);
+ ScopeTree::Ptr scope(new ScopeTree(ScopeType::QMLScope));
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *component = cast<UiObjectDefinition *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (component) {
QString name = toString(component->qualifiedTypeNameId);
if (name == QLatin1String("Property"))
- readProperty(component, fmo);
+ readProperty(component, scope);
else if (name == QLatin1String("Method") || name == QLatin1String("Signal"))
- readSignalOrMethod(component, name == QLatin1String("Method"), fmo);
+ readSignalOrMethod(component, name == QLatin1String("Method"), scope);
else if (name == QLatin1String("Enum"))
- readEnum(component, fmo);
+ readEnum(component, scope);
else
addWarning(component->firstSourceLocation(),
- tr("Expected only Property, Method, Signal and Enum object definitions, not \"%1\".")
- .arg(name));
+ tr("Expected only Property, Method, Signal and Enum object definitions, "
+ "not \"%1\".").arg(name));
} else if (script) {
QString name = toString(script->qualifiedId);
if (name == QLatin1String("name")) {
- fmo->setClassName(readStringBinding(script));
+ scope->setClassName(readStringBinding(script));
} else if (name == QLatin1String("prototype")) {
- fmo->setSuperclassName(readStringBinding(script));
+ scope->setSuperclassName(readStringBinding(script));
} else if (name == QLatin1String("defaultProperty")) {
- fmo->setDefaultPropertyName(readStringBinding(script));
+ scope->setDefaultPropertyName(readStringBinding(script));
} else if (name == QLatin1String("exports")) {
- readExports(script, fmo);
+ readExports(script, scope);
} else if (name == QLatin1String("exportMetaObjectRevisions")) {
- readMetaObjectRevisions(script, fmo);
+ readMetaObjectRevisions(script, scope);
} else if (name == QLatin1String("attachedType")) {
- fmo->setAttachedTypeName(readStringBinding(script));
+ scope->setAttachedTypeName(readStringBinding(script));
} else if (name == QLatin1String("isSingleton")) {
- fmo->setIsSingleton(readBoolBinding(script));
+ scope->setIsSingleton(readBoolBinding(script));
} else if (name == QLatin1String("isCreatable")) {
- fmo->setIsCreatable(readBoolBinding(script));
+ scope->setIsCreatable(readBoolBinding(script));
} else if (name == QLatin1String("isComposite")) {
- fmo->setIsComposite(readBoolBinding(script));
+ scope->setIsComposite(readBoolBinding(script));
} else {
addWarning(script->firstSourceLocation(),
- tr("Expected only name, prototype, defaultProperty, attachedType, exports, "
- "isSingleton, isCreatable, isComposite and exportMetaObjectRevisions "
- "script bindings, not \"%1\".").arg(name));
+ tr("Expected only name, prototype, defaultProperty, attachedType, "
+ "exports, isSingleton, isCreatable, isComposite and "
+ "exportMetaObjectRevisions script bindings, not \"%1\".").arg(name));
}
} else {
- addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
+ addWarning(member->firstSourceLocation(),
+ tr("Expected only script bindings and object definitions."));
}
}
- if (fmo->className().isEmpty()) {
+ if (scope->className().isEmpty()) {
addError(ast->firstSourceLocation(), tr("Component definition is missing a name binding."));
return;
}
// ### add implicit export into the package of c++ types
- fmo->addExport(fmo->className(), QStringLiteral("<cpp>"), ComponentVersion());
- fmo->updateFingerprint();
- _objects->insert(fmo->className(), fmo);
+ scope->addExport(scope->className(), QStringLiteral("<cpp>"), ComponentVersion());
+ m_objects->insert(scope->className(), scope);
}
void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
@@ -284,7 +259,7 @@ void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (script) {
const QString name = toString(script->qualifiedId);
@@ -304,58 +279,65 @@ void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
}
if (!apiInfo.version.isValid()) {
- addError(ast->firstSourceLocation(), tr("ModuleApi definition has no or invalid version binding."));
+ addError(ast->firstSourceLocation(),
+ tr("ModuleApi definition has no or invalid version binding."));
return;
}
- if (_moduleApis)
- _moduleApis->append(apiInfo);
+ if (m_moduleApis)
+ m_moduleApis->append(apiInfo);
}
-void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod,
+ const ScopeTree::Ptr &scope)
{
- FakeMetaMethod fmm;
+ MetaMethod metaMethod;
// ### confusion between Method and Slot. Method should be removed.
if (isMethod)
- fmm.setMethodType(FakeMetaMethod::Slot);
+ metaMethod.setMethodType(MetaMethod::Slot);
else
- fmm.setMethodType(FakeMetaMethod::Signal);
+ metaMethod.setMethodType(MetaMethod::Signal);
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiObjectDefinition *component = AST::cast<UiObjectDefinition *>(member);
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *component = cast<UiObjectDefinition *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (component) {
QString name = toString(component->qualifiedTypeNameId);
- if (name == QLatin1String("Parameter"))
- readParameter(component, &fmm);
- else
- addWarning(component->firstSourceLocation(), tr("Expected only Parameter object definitions."));
+ if (name == QLatin1String("Parameter")) {
+ readParameter(component, &metaMethod);
+ } else {
+ addWarning(component->firstSourceLocation(),
+ tr("Expected only Parameter object definitions."));
+ }
} else if (script) {
QString name = toString(script->qualifiedId);
- if (name == QLatin1String("name"))
- fmm.setMethodName(readStringBinding(script));
- else if (name == QLatin1String("type"))
- fmm.setReturnType(readStringBinding(script));
- else if (name == QLatin1String("revision"))
- fmm.setRevision(readIntBinding(script));
- else
- addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
-
+ if (name == QLatin1String("name")) {
+ metaMethod.setMethodName(readStringBinding(script));
+ } else if (name == QLatin1String("type")) {
+ metaMethod.setReturnType(readStringBinding(script));
+ } else if (name == QLatin1String("revision")) {
+ metaMethod.setRevision(readIntBinding(script));
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only name and type script bindings."));
+ }
} else {
- addWarning(member->firstSourceLocation(), tr("Expected only script bindings and object definitions."));
+ addWarning(member->firstSourceLocation(),
+ tr("Expected only script bindings and object definitions."));
}
}
- if (fmm.methodName().isEmpty()) {
- addError(ast->firstSourceLocation(), tr("Method or signal is missing a name script binding."));
+ if (metaMethod.methodName().isEmpty()) {
+ addError(ast->firstSourceLocation(),
+ tr("Method or signal is missing a name script binding."));
return;
}
- fmo->addMethod(fmm);
+ scope->addMethod(metaMethod);
}
-void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, const ScopeTree::Ptr &scope)
{
QString name;
QString type;
@@ -366,69 +348,75 @@ void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (!script) {
addWarning(member->firstSourceLocation(), tr("Expected script binding."));
continue;
}
QString id = toString(script->qualifiedId);
- if (id == QLatin1String("name"))
+ if (id == QLatin1String("name")) {
name = readStringBinding(script);
- else if (id == QLatin1String("type"))
+ } else if (id == QLatin1String("type")) {
type = readStringBinding(script);
- else if (id == QLatin1String("isPointer"))
+ } else if (id == QLatin1String("isPointer")) {
isPointer = readBoolBinding(script);
- else if (id == QLatin1String("isReadonly"))
+ } else if (id == QLatin1String("isReadonly")) {
isReadonly = readBoolBinding(script);
- else if (id == QLatin1String("isList"))
+ } else if (id == QLatin1String("isList")) {
isList = readBoolBinding(script);
- else if (id == QLatin1String("revision"))
+ } else if (id == QLatin1String("revision")) {
revision = readIntBinding(script);
- else
- addWarning(script->firstSourceLocation(), tr("Expected only type, name, revision, isPointer, isReadonly and isList script bindings."));
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only type, name, revision, isPointer, isReadonly and"
+ " isList script bindings."));
+ }
}
if (name.isEmpty() || type.isEmpty()) {
- addError(ast->firstSourceLocation(), tr("Property object is missing a name or type script binding."));
+ addError(ast->firstSourceLocation(),
+ tr("Property object is missing a name or type script binding."));
return;
}
- fmo->addProperty(FakeMetaProperty(name, type, isList, !isReadonly, isPointer, revision));
+ scope->addProperty(MetaProperty(name, type, isList, !isReadonly, isPointer, revision));
}
-void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, const ScopeTree::Ptr &scope)
{
- FakeMetaEnum fme;
+ MetaEnum metaEnum;
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (!script) {
addWarning(member->firstSourceLocation(), tr("Expected script binding."));
continue;
}
QString name = toString(script->qualifiedId);
- if (name == QLatin1String("name"))
- fme.setName(readStringBinding(script));
- else if (name == QLatin1String("values"))
- readEnumValues(script, &fme);
- else
- addWarning(script->firstSourceLocation(), tr("Expected only name and values script bindings."));
+ if (name == QLatin1String("name")) {
+ metaEnum.setName(readStringBinding(script));
+ } else if (name == QLatin1String("values")) {
+ readEnumValues(script, &metaEnum);
+ } else {
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only name and values script bindings."));
+ }
}
- fmo->addEnum(fme);
+ scope->addEnum(metaEnum);
}
-void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMethod *fmm)
+void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, MetaMethod *metaMethod)
{
QString name;
QString type;
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
- UiScriptBinding *script = AST::cast<UiScriptBinding *>(member);
+ auto *script = cast<UiScriptBinding *>(member);
if (!script) {
addWarning(member->firstSourceLocation(), tr("Expected script binding."));
continue;
@@ -446,29 +434,30 @@ void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMetho
} else if (id == QLatin1String("isList")) {
// ### unhandled
} else {
- addWarning(script->firstSourceLocation(), tr("Expected only name and type script bindings."));
+ addWarning(script->firstSourceLocation(),
+ tr("Expected only name and type script bindings."));
}
}
- fmm->addParameter(name, type);
+ metaMethod->addParameter(name, type);
}
QString TypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
{
- QTC_ASSERT(ast, return QString());
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected string after colon."));
return QString();
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
addError(ast->statement->firstSourceLocation(), tr("Expected string after colon."));
return QString();
}
- StringLiteral *stringLit = AST::cast<StringLiteral *>(expStmt->expression);
+ auto *stringLit = cast<StringLiteral *>(expStmt->expression);
if (!stringLit) {
addError(expStmt->firstSourceLocation(), tr("Expected string after colon."));
return QString();
@@ -477,23 +466,23 @@ QString TypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
return stringLit->value.toString();
}
-bool TypeDescriptionReader::readBoolBinding(AST::UiScriptBinding *ast)
+bool TypeDescriptionReader::readBoolBinding(UiScriptBinding *ast)
{
- QTC_ASSERT(ast, return false);
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected boolean after colon."));
return false;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
addError(ast->statement->firstSourceLocation(), tr("Expected boolean after colon."));
return false;
}
- TrueLiteral *trueLit = AST::cast<TrueLiteral *>(expStmt->expression);
- FalseLiteral *falseLit = AST::cast<FalseLiteral *>(expStmt->expression);
+ auto *trueLit = cast<TrueLiteral *>(expStmt->expression);
+ auto *falseLit = cast<FalseLiteral *>(expStmt->expression);
if (!trueLit && !falseLit) {
addError(expStmt->firstSourceLocation(), tr("Expected true or false after colon."));
return false;
@@ -502,22 +491,23 @@ bool TypeDescriptionReader::readBoolBinding(AST::UiScriptBinding *ast)
return trueLit;
}
-double TypeDescriptionReader::readNumericBinding(AST::UiScriptBinding *ast)
+double TypeDescriptionReader::readNumericBinding(UiScriptBinding *ast)
{
- QTC_ASSERT(ast, return qQNaN());
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected numeric literal after colon."));
return 0;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected numeric literal after colon."));
return 0;
}
- NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
+ auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
if (!numericLit) {
addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
return 0;
@@ -531,26 +521,29 @@ ComponentVersion TypeDescriptionReader::readNumericVersionBinding(UiScriptBindin
ComponentVersion invalidVersion;
if (!ast || !ast->statement) {
- addError((ast ? ast->colonToken : SourceLocation()), tr("Expected numeric literal after colon."));
+ addError((ast ? ast->colonToken : SourceLocation()),
+ tr("Expected numeric literal after colon."));
return invalidVersion;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected numeric literal after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected numeric literal after colon."));
return invalidVersion;
}
- NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
+ auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
if (!numericLit) {
addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
return invalidVersion;
}
- return ComponentVersion(_source.mid(numericLit->literalToken.begin(), numericLit->literalToken.length));
+ return ComponentVersion(m_source.mid(numericLit->literalToken.begin(),
+ numericLit->literalToken.length));
}
-int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast)
+int TypeDescriptionReader::readIntBinding(UiScriptBinding *ast)
{
double v = readNumericBinding(ast);
int i = static_cast<int>(v);
@@ -563,31 +556,33 @@ int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast)
return i;
}
-void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readExports(UiScriptBinding *ast, const ScopeTree::Ptr &scope)
{
- QTC_ASSERT(ast, return);
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected array of strings after colon."));
return;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected array of strings after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected array of strings after colon."));
return;
}
- ArrayPattern *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression);
+ auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
if (!arrayLit) {
addError(expStmt->firstSourceLocation(), tr("Expected array of strings after colon."));
return;
}
for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
- StringLiteral *stringLit = AST::cast<StringLiteral *>(it->element->initializer);
+ auto *stringLit = cast<StringLiteral *>(it->element->initializer);
if (!stringLit) {
- addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only string literal members."));
+ addError(arrayLit->firstSourceLocation(),
+ tr("Expected array literal with only string literal members."));
return;
}
QString exp = stringLit->value.toString();
@@ -596,7 +591,9 @@ void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Pt
ComponentVersion version(exp.mid(spaceIdx + 1));
if (spaceIdx == -1 || !version.isValid()) {
- addError(stringLit->firstSourceLocation(), tr("Expected string literal to contain 'Package/Name major.minor' or 'Name major.minor'."));
+ addError(stringLit->firstSourceLocation(),
+ tr("Expected string literal to contain 'Package/Name major.minor' "
+ "or 'Name major.minor'."));
continue;
}
QString package;
@@ -605,42 +602,46 @@ void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Pt
QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
// ### relocatable exports where package is empty?
- fmo->addExport(name, package, version);
+ scope->addExport(name, package, version);
}
}
-void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
+void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast,
+ const ScopeTree::Ptr &scope)
{
- QTC_ASSERT(ast, return);
+ Q_ASSERT(ast);
if (!ast->statement) {
addError(ast->colonToken, tr("Expected array of numbers after colon."));
return;
}
- ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
- addError(ast->statement->firstSourceLocation(), tr("Expected array of numbers after colon."));
+ addError(ast->statement->firstSourceLocation(),
+ tr("Expected array of numbers after colon."));
return;
}
- ArrayPattern *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression);
+ auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
if (!arrayLit) {
addError(expStmt->firstSourceLocation(), tr("Expected array of numbers after colon."));
return;
}
int exportIndex = 0;
- const int exportCount = fmo->exports().size();
+ const int exportCount = scope->exports().size();
for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
- NumericLiteral *numberLit = cast<NumericLiteral *>(it->element->initializer);
+ auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
if (!numberLit) {
- addError(arrayLit->firstSourceLocation(), tr("Expected array literal with only number literal members."));
+ addError(arrayLit->firstSourceLocation(),
+ tr("Expected array literal with only number literal members."));
return;
}
if (exportIndex >= exportCount) {
- addError(numberLit->firstSourceLocation(), tr("Meta object revision without matching export."));
+ addError(numberLit->firstSourceLocation(),
+ tr("Meta object revision without matching export."));
return;
}
@@ -651,11 +652,11 @@ void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMe
return;
}
- fmo->setExportMetaObjectRevision(exportIndex, metaObjectRevision);
+ scope->setExportMetaObjectRevision(exportIndex, metaObjectRevision);
}
}
-void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme)
+void TypeDescriptionReader::readEnumValues(UiScriptBinding *ast, MetaEnum *metaEnum)
{
if (!ast)
return;
@@ -664,27 +665,27 @@ void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUt
return;
}
- auto *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
+ auto *expStmt = cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
addError(ast->statement->firstSourceLocation(), tr("Expected expression after colon."));
return;
}
- if (auto *objectLit = AST::cast<ObjectPattern *>(expStmt->expression)) {
+ if (auto *objectLit = cast<ObjectPattern *>(expStmt->expression)) {
for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
if (PatternProperty *assignement = it->property) {
- if (auto *name = AST::cast<StringLiteralPropertyName *>(assignement->name)) {
- fme->addKey(name->id.toString());
+ if (auto *name = cast<StringLiteralPropertyName *>(assignement->name)) {
+ metaEnum->addKey(name->id.toString());
continue;
}
}
addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
}
- } else if (auto *arrayLit = AST::cast<ArrayPattern *>(expStmt->expression)) {
+ } else if (auto *arrayLit = cast<ArrayPattern *>(expStmt->expression)) {
for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
if (PatternElement *element = it->element) {
- if (auto *name = AST::cast<StringLiteral *>(element->initializer)) {
- fme->addKey(name->value.toString());
+ if (auto *name = cast<StringLiteral *>(element->initializer)) {
+ metaEnum->addKey(name->value.toString());
continue;
}
}
diff --git a/tools/qmllint/typedescriptionreader.h b/tools/qmllint/typedescriptionreader.h
new file mode 100644
index 0000000000..5fcbe3abc9
--- /dev/null
+++ b/tools/qmllint/typedescriptionreader.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TYPEDESCRIPTIONREADER_H
+#define TYPEDESCRIPTIONREADER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include "scopetree.h"
+
+#include <QtQml/private/qqmljsastfwd_p.h>
+
+// for Q_DECLARE_TR_FUNCTIONS
+#include <QtCore/qcoreapplication.h>
+
+struct ModuleApiInfo
+{
+ QString uri;
+ ComponentVersion version;
+ QString cppName;
+};
+
+class TypeDescriptionReader
+{
+ Q_DECLARE_TR_FUNCTIONS(TypeDescriptionReader)
+public:
+ TypeDescriptionReader() = default;
+ explicit TypeDescriptionReader(QString fileName, QString data)
+ : m_fileName(std::move(fileName)), m_source(std::move(data)) {}
+
+ bool operator()(
+ QHash<QString, ScopeTree::ConstPtr> *objects,
+ QList<ModuleApiInfo> *moduleApis,
+ QStringList *dependencies);
+
+ QString errorMessage() const { return m_errorMessage; }
+ QString warningMessage() const { return m_warningMessage; }
+
+private:
+ void readDocument(QQmlJS::AST::UiProgram *ast);
+ void readModule(QQmlJS::AST::UiObjectDefinition *ast);
+ void readDependencies(QQmlJS::AST::UiScriptBinding *ast);
+ void readComponent(QQmlJS::AST::UiObjectDefinition *ast);
+ void readModuleApi(QQmlJS::AST::UiObjectDefinition *ast);
+ void readSignalOrMethod(QQmlJS::AST::UiObjectDefinition *ast, bool isMethod,
+ const ScopeTree::Ptr &scope);
+ void readProperty(QQmlJS::AST::UiObjectDefinition *ast, const ScopeTree::Ptr &scope);
+ void readEnum(QQmlJS::AST::UiObjectDefinition *ast, const ScopeTree::Ptr &scope);
+ void readParameter(QQmlJS::AST::UiObjectDefinition *ast, MetaMethod *metaMethod);
+
+ QString readStringBinding(QQmlJS::AST::UiScriptBinding *ast);
+ bool readBoolBinding(QQmlJS::AST::UiScriptBinding *ast);
+ double readNumericBinding(QQmlJS::AST::UiScriptBinding *ast);
+ ComponentVersion readNumericVersionBinding(QQmlJS::AST::UiScriptBinding *ast);
+ int readIntBinding(QQmlJS::AST::UiScriptBinding *ast);
+ void readExports(QQmlJS::AST::UiScriptBinding *ast, const ScopeTree::Ptr &scope);
+ void readMetaObjectRevisions(QQmlJS::AST::UiScriptBinding *ast, const ScopeTree::Ptr &scope);
+ void readEnumValues(QQmlJS::AST::UiScriptBinding *ast, MetaEnum *metaEnum);
+
+ void addError(const QQmlJS::AST::SourceLocation &loc, const QString &message);
+ void addWarning(const QQmlJS::AST::SourceLocation &loc, const QString &message);
+
+ QString m_fileName;
+ QString m_source;
+ QString m_errorMessage;
+ QString m_warningMessage;
+ QHash<QString, ScopeTree::ConstPtr> *m_objects = nullptr;
+ QList<ModuleApiInfo> *m_moduleApis = nullptr;
+ QStringList *m_dependencies = nullptr;
+};
+
+#endif // TYPEDESCRIPTIONREADER_H