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>
This commit is contained in:
parent
61d7713ead
commit
6fb335ebce
|
@ -128,10 +128,10 @@ void TestQmllint::dirtyQmlCode_data()
|
|||
<< QStringLiteral("failure1.js")
|
||||
<< QStringLiteral("failure1.js:4 : Expected token `;'")
|
||||
<< QString();
|
||||
QTest::newRow("UnmatchedSignalHandler")
|
||||
<< QStringLiteral("UnmatchedSignalHandler.qml")
|
||||
<< QString("Warning: no matching signal found for handler \"onClicked\" at 12:13")
|
||||
<< QStringLiteral("onMouseXChanged");
|
||||
QTest::newRow("AutomatchedSignalHandler")
|
||||
<< QStringLiteral("AutomatchedSignalHandler.qml")
|
||||
<< QString("Warning: unqualified access at 12:36")
|
||||
<< QStringLiteral("no matching signal found");
|
||||
}
|
||||
|
||||
void TestQmllint::dirtyQmlCode()
|
||||
|
|
|
@ -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;
|
||||
m_major = maybeMajor;
|
||||
m_minor = maybeMinor;
|
||||
}
|
||||
|
||||
ComponentVersion::~ComponentVersion()
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
if (scope) {
|
||||
const auto properties = scope->properties();
|
||||
for (const auto &property : properties)
|
||||
m_currentScope->insertPropertyIdentifier(property);
|
||||
|
||||
m_currentScope->addMethodsFromMetaObject(metaObject);
|
||||
|
||||
name = metaObject->superclassName();
|
||||
if (name.isEmpty() || name == QLatin1String("QObject")) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -29,32 +29,41 @@
|
|||
#ifndef FINDUNQUALIFIED_H
|
||||
#define FINDUNQUALIFIED_H
|
||||
|
||||
#include "qmljstypedescriptionreader.h"
|
||||
#include "qcoloroutput_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 <private/qqmljsastvisitor_p.h>
|
||||
#include <private/qqmljsast_p.h>
|
||||
#include "typedescriptionreader.h"
|
||||
#include "scopetree.h"
|
||||
#include "qcoloroutput.h"
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <QtQml/private/qqmljsastvisitor_p.h>
|
||||
#include <QtQml/private/qqmljsast_p.h>
|
||||
|
||||
class ScopeTree;
|
||||
enum class ScopeType;
|
||||
|
||||
class FindUnqualifiedIDVisitor : public QQmlJS::AST::Visitor {
|
||||
#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
|
||||
|
|
|
@ -26,27 +26,29 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#if QT_CONFIG(commandlineparser)
|
||||
#include <QCommandLineParser>
|
||||
#endif
|
||||
#include <QCoreApplication>
|
||||
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
#include <QLibraryInfo>
|
||||
#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)
|
||||
#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 <QtCore/qcommandlineparser.h>
|
||||
#endif
|
||||
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
#include <QtCore/qlibraryinfo.h>
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
@ -214,41 +217,18 @@ const char *const ColorOutputPrivate::backgrounds[] =
|
|||
on the settings of the user's terminal.
|
||||
*/
|
||||
|
||||
/*!
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
bool ScopeTree::isIdInjectedFromSignal(const QString &id) const
|
||||
{
|
||||
auto qmlScope = getCurrentQMLScope();
|
||||
return qmlScope->m_injectedSignalIdentifiers.contains(id);
|
||||
return currentQMLScope()->m_injectedSignalIdentifiers.contains(id);
|
||||
}
|
||||
|
||||
const ScopeTree *ScopeTree::getCurrentQMLScope() const
|
||||
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;
|
||||
}
|
||||
|
||||
ScopeTree *ScopeTree::getCurrentQMLScope()
|
||||
{
|
||||
auto qmlScope = this;
|
||||
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::addMethod(LanguageUtils::FakeMetaMethod method)
|
||||
void ScopeTree::addExport(const QString &name, const QString &package,
|
||||
const ComponentVersion &version)
|
||||
{
|
||||
m_methods.insert(method.methodName(), method);
|
||||
m_exports.append(Export(package, name, version, 0));
|
||||
}
|
||||
|
||||
void ScopeTree::addMethodsFromMetaObject(LanguageUtils::FakeMetaObject::ConstPtr metaObject)
|
||||
void ScopeTree::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
|
||||
{
|
||||
if (metaObject) {
|
||||
auto methodCount = metaObject->methodCount();
|
||||
for (auto i = 0; i < methodCount; ++i) {
|
||||
auto method = metaObject->method(i);
|
||||
this->addMethod(method);
|
||||
}
|
||||
}
|
||||
m_exports[exportIndex].setMetaObjectRevision(metaObjectRevision);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
bool ScopeTree::Export::isValid() const
|
||||
{
|
||||
return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
||||
ScopeTree* createNewChildScope(ScopeType type, QString name);
|
||||
ScopeTree* parentScope();
|
||||
class Export {
|
||||
public:
|
||||
Export() = default;
|
||||
Export(QString package, QString type, const ComponentVersion &version,
|
||||
int metaObjectRevision);
|
||||
|
||||
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
|
||||
bool isValid() const;
|
||||
|
||||
int metaObjectRevision() const { return m_metaObjectRevision; }
|
||||
void setMetaObjectRevision(int metaObjectRevision)
|
||||
{
|
||||
m_metaObjectRevision = metaObjectRevision;
|
||||
}
|
||||
|
||||
QString package() const { return m_package; }
|
||||
QString type() const { return m_type; }
|
||||
|
||||
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, 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;
|
||||
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; }
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue