qmljs: update Qml parser to parser of Qt 6.2

this is needed (among other things) for
 * null coalescing
 * shebang support

Change-Id: I1b37fd86593f143de8b39c0daf433831a8785568
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Fawzi Mohamed
2021-07-06 23:50:30 +02:00
parent dc654cfcba
commit af88a7876b
32 changed files with 3769 additions and 3415 deletions

View File

@@ -4,6 +4,7 @@ add_qtc_library(QmlJS
SOURCES SOURCES
jsoncheck.cpp jsoncheck.h jsoncheck.cpp jsoncheck.h
parser/qmldirparser.cpp parser/qmldirparser_p.h parser/qmldirparser.cpp parser/qmldirparser_p.h
parser/qmlimportresolver.cpp parser/qmlimportresolver_p.h
parser/qmljsast.cpp parser/qmljsast_p.h parser/qmljsast.cpp parser/qmljsast_p.h
parser/qmljsastfwd_p.h parser/qmljsastfwd_p.h
parser/qmljsastvisitor.cpp parser/qmljsastvisitor_p.h parser/qmljsastvisitor.cpp parser/qmljsastvisitor_p.h

View File

@@ -3,6 +3,7 @@ HEADERS += \
$$PWD/qmljsastfwd_p.h \ $$PWD/qmljsastfwd_p.h \
$$PWD/qmljsastvisitor_p.h \ $$PWD/qmljsastvisitor_p.h \
$$PWD/qmljsengine_p.h \ $$PWD/qmljsengine_p.h \
$$PWD/qmlimportresolver_p.h \
$$PWD/qmljslexer_p.h \ $$PWD/qmljslexer_p.h \
$$PWD/qmljsglobal_p.h \ $$PWD/qmljsglobal_p.h \
$$PWD/qmljssourcelocation_p.h \ $$PWD/qmljssourcelocation_p.h \
@@ -16,6 +17,7 @@ SOURCES += \
$$PWD/qmljsast.cpp \ $$PWD/qmljsast.cpp \
$$PWD/qmljsastvisitor.cpp \ $$PWD/qmljsastvisitor.cpp \
$$PWD/qmljsengine_p.cpp \ $$PWD/qmljsengine_p.cpp \
$$PWD/qmlimportresolver.cpp \
$$PWD/qmljslexer.cpp \ $$PWD/qmljslexer.cpp \
$$PWD/qmldirparser.cpp \ $$PWD/qmldirparser.cpp \
$$PWD/qmljsgrammar.cpp \ $$PWD/qmljsgrammar.cpp \

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -102,7 +102,7 @@ void QmlDirParser::clear()
_plugins.clear(); _plugins.clear();
_designerSupported = false; _designerSupported = false;
_typeInfos.clear(); _typeInfos.clear();
_className.clear(); _classNames.clear();
} }
inline static void scanSpace(const QChar *&ch) { inline static void scanSpace(const QChar *&ch) {
@@ -258,7 +258,6 @@ bool QmlDirParser::parse(const QString &source)
"not %1.").arg(sections[1])); "not %1.").arg(sections[1]));
continue; continue;
} }
} else if (sections[0] == QLatin1String("classname")) { } else if (sections[0] == QLatin1String("classname")) {
if (sectionCount < 2) { if (sectionCount < 2) {
reportError(lineNumber, 0, reportError(lineNumber, 0,
@@ -267,7 +266,7 @@ bool QmlDirParser::parse(const QString &source)
continue; continue;
} }
_className = sections[1]; _classNames.append(sections[1]);
} else if (sections[0] == QLatin1String("internal")) { } else if (sections[0] == QLatin1String("internal")) {
if (sectionCount != 3) { if (sectionCount != 3) {
@@ -308,19 +307,38 @@ bool QmlDirParser::parse(const QString &source)
QStringLiteral("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1)); QStringLiteral("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
continue; continue;
} }
#ifdef QT_CREATOR _typeInfos.append(sections[1]);
TypeInfo typeInfo(sections[1]);
_typeInfos.append(typeInfo);
#endif
} else if (sections[0] == QLatin1String("designersupported")) { } else if (sections[0] == QLatin1String("designersupported")) {
if (sectionCount != 1) if (sectionCount != 1)
reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument")); reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument"));
else else
_designerSupported = true; _designerSupported = true;
} else if (sections[0] == QLatin1String("depends") || sections[0] == QLatin1String("import")) { } else if (sections[0] == QLatin1String("import")
|| sections[0] == QLatin1String("depends")) {
if (!readImport(sections, sectionCount, Import::Default)) if (!readImport(sections, sectionCount, Import::Default))
continue; continue;
} else if (sections[0] == QLatin1String("prefer")) {
if (sectionCount < 2) {
reportError(lineNumber, 0,
QStringLiteral("prefer directive requires one argument, "
"but %1 were provided").arg(sectionCount - 1));
continue;
}
if (!_preferredPath.isEmpty()) {
reportError(lineNumber, 0, QStringLiteral(
"only one prefer directive may be defined in a qmldir file"));
continue;
}
if (!sections[1].endsWith(u'/')) {
// Yes. People should realize it's a directory.
reportError(lineNumber, 0, QStringLiteral(
"the preferred directory has to end with a '/'"));
continue;
}
_preferredPath = sections[1];
} else if (sectionCount == 2) { } else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files) // No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1); const Component entry(sections[0], sections[1], -1, -1);
@@ -361,14 +379,6 @@ void QmlDirParser::reportError(quint16 line, quint16 column, const QString &desc
_errors.append(error); _errors.append(error);
} }
bool QmlDirParser::hasError() const
{
if (! _errors.isEmpty())
return true;
return false;
}
void QmlDirParser::setError(const QmlJS::DiagnosticMessage &e) void QmlDirParser::setError(const QmlJS::DiagnosticMessage &e)
{ {
_errors.clear(); _errors.clear();
@@ -388,56 +398,6 @@ QList<QmlJS::DiagnosticMessage> QmlDirParser::errors(const QString &uri) const
return errors; return errors;
} }
QString QmlDirParser::typeNamespace() const
{
return _typeNamespace;
}
void QmlDirParser::setTypeNamespace(const QString &s)
{
_typeNamespace = s;
}
QList<QmlDirParser::Plugin> QmlDirParser::plugins() const
{
return _plugins;
}
QMultiHash<QString, QmlDirParser::Component> QmlDirParser::components() const
{
return _components;
}
QList<QmlDirParser::Import> QmlDirParser::dependencies() const
{
return _dependencies;
}
QList<QmlDirParser::Import> QmlDirParser::imports() const
{
return _imports;
}
QList<QmlDirParser::Script> QmlDirParser::scripts() const
{
return _scripts;
}
QList<QmlDirParser::TypeInfo> QmlDirParser::typeInfos() const
{
return _typeInfos;
}
bool QmlDirParser::designerSupported() const
{
return _designerSupported;
}
QString QmlDirParser::className() const
{
return _className;
}
QDebug &operator<< (QDebug &debug, const QmlDirParser::Component &component) QDebug &operator<< (QDebug &debug, const QmlDirParser::Component &component)
{ {
const QString output = QStringLiteral("{%1 %2.%3}"). const QString output = QStringLiteral("{%1 %2.%3}").

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -55,12 +55,12 @@ public:
void clear(); void clear();
bool parse(const QString &source); bool parse(const QString &source);
bool hasError() const; bool hasError() const { return !_errors.isEmpty(); }
void setError(const QmlJS::DiagnosticMessage &); void setError(const QmlJS::DiagnosticMessage &);
QList<QmlJS::DiagnosticMessage> errors(const QString &uri) const; QList<QmlJS::DiagnosticMessage> errors(const QString &uri) const;
QString typeNamespace() const; QString typeNamespace() const { return _typeNamespace; }
void setTypeNamespace(const QString &s); void setTypeNamespace(const QString &s) { _typeNamespace = s; }
static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName) static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName)
{ {
@@ -141,25 +141,16 @@ public:
Flags flags; Flags flags;
}; };
QMultiHash<QString,Component> components() const; QMultiHash<QString,Component> components() const { return _components; }
QList<Import> dependencies() const; QList<Import> dependencies() const { return _dependencies; }
QList<Import> imports() const; QList<Import> imports() const { return _imports; }
QList<Script> scripts() const; QList<Script> scripts() const { return _scripts; }
QList<Plugin> plugins() const; QList<Plugin> plugins() const { return _plugins; }
bool designerSupported() const; bool designerSupported() const { return _designerSupported; }
struct TypeInfo QStringList typeInfos() const { return _typeInfos; }
{ QStringList classNames() const { return _classNames; }
TypeInfo() = default; QString preferredPath() const { return _preferredPath; }
TypeInfo(const QString &fileName)
: fileName(fileName) {}
QString fileName;
};
QList<TypeInfo> typeInfos() const;
QString className() const;
private: private:
bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true); bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true);
@@ -168,19 +159,21 @@ private:
private: private:
QList<QmlJS::DiagnosticMessage> _errors; QList<QmlJS::DiagnosticMessage> _errors;
QString _typeNamespace; QString _typeNamespace;
QString _preferredPath;
QMultiHash<QString,Component> _components; QMultiHash<QString,Component> _components;
QList<Import> _dependencies; QList<Import> _dependencies;
QList<Import> _imports; QList<Import> _imports;
QList<Script> _scripts; QList<Script> _scripts;
QList<Plugin> _plugins; QList<Plugin> _plugins;
bool _designerSupported = false; bool _designerSupported = false;
QList<TypeInfo> _typeInfos; QStringList _typeInfos;
QString _className; QStringList _classNames;
}; };
using QmlDirComponents = QMultiHash<QString,QmlDirParser::Component>; using QmlDirComponents = QMultiHash<QString,QmlDirParser::Component>;
using QmlDirScripts = QList<QmlDirParser::Script>; using QmlDirScripts = QList<QmlDirParser::Script>;
using QmlDirPlugins = QList<QmlDirParser::Plugin>; using QmlDirPlugins = QList<QmlDirParser::Plugin>;
using QmlDirImports = QList<QmlDirParser::Import>;
QDebug &operator<< (QDebug &, const QmlDirParser::Component &); QDebug &operator<< (QDebug &, const QmlDirParser::Component &);
QDebug &operator<< (QDebug &, const QmlDirParser::Script &); QDebug &operator<< (QDebug &, const QmlDirParser::Script &);

View File

@@ -0,0 +1,108 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** 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.
**
****************************************************************************/
#include "qmlimportresolver_p.h"
QT_QML_BEGIN_NAMESPACE
enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
/*!
Forms complete paths to a module, from a list of base paths,
a module URI and version specification.
For example, QtQml.Models 2.0:
- base/QtQml/Models.2.0
- base/QtQml.2.0/Models
- base/QtQml/Models.2
- base/QtQml.2/Models
- base/QtQml/Models
*/
QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths,
LanguageUtils::ComponentVersion version)
{
static const QLatin1Char Slash('/');
static const QLatin1Char Backslash('\\');
const QList<QStringView> parts = uri.split(u'.', Qt::SkipEmptyParts);
QStringList importPaths;
// fully & partially versioned parts + 1 unversioned for each base path
importPaths.reserve(2 * parts.count() + 1);
auto versionString = [](LanguageUtils::ComponentVersion version, ImportVersion mode)
{
if (mode == FullyVersioned) {
// extension with fully encoded version number (eg. MyModule.3.2)
return QString::fromLatin1(".%1.%2").arg(version.majorVersion())
.arg(version.minorVersion());
}
if (mode == PartiallyVersioned) {
// extension with encoded version major (eg. MyModule.3)
return QString::fromLatin1(".%1").arg(version.majorVersion());
}
// else extension without version number (eg. MyModule)
return QString();
};
auto joinStringRefs = [](const QList<QStringView> &refs, const QChar &sep) {
QString str;
for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
if (it != refs.cbegin())
str += sep;
str += *it;
}
return str;
};
const ImportVersion initial = ((version.minorVersion() >= 0)
? FullyVersioned
: ((version.majorVersion() >= 0) ? PartiallyVersioned : Unversioned));
for (int mode = initial; mode <= Unversioned; ++mode) {
const QString ver = versionString(version, ImportVersion(mode));
for (const QString &path : basePaths) {
QString dir = path;
if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
dir += Slash;
// append to the end
importPaths += dir + joinStringRefs(parts, Slash) + ver;
if (mode != Unversioned) {
// insert in the middle
for (int index = parts.count() - 2; index >= 0; --index) {
importPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
+ ver + Slash
+ joinStringRefs(parts.mid(index + 1), Slash);
}
}
}
}
return importPaths;
}
QT_QML_END_NAMESPACE

View File

@@ -0,0 +1,50 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** 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.
**
****************************************************************************/
#pragma once
//
// 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 "qmljs/parser/qmljsglobal_p.h"
#include "qmljsglobal_p.h"
#include <QtCore/qstring.h>
#include <languageutils/componentversion.h>
QT_QML_BEGIN_NAMESPACE
QML_PARSER_EXPORT QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths,
LanguageUtils::ComponentVersion version);
QT_QML_END_NAMESPACE

View File

@@ -81,6 +81,7 @@
%token T_COMPATIBILITY_SEMICOLON %token T_COMPATIBILITY_SEMICOLON
%token T_ARROW "=>" %token T_ARROW "=>"
%token T_QUESTION_QUESTION "??" %token T_QUESTION_QUESTION "??"
%token T_QUESTION_DOT "?."
%token T_ENUM "enum" %token T_ENUM "enum"
%token T_ELLIPSIS "..." %token T_ELLIPSIS "..."
%token T_YIELD "yield" %token T_YIELD "yield"
@@ -835,18 +836,32 @@ UiImport: UiImportHead Semicolon;
UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER; UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER;
/. /.
case $rule_number: { case $rule_number: {
auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, sym(3).dval); const int major = sym(1).dval;
const int minor = sym(3).dval;
if (major < 0 || major >= 255 || minor < 0 || minor >= 255) {
diagnostic_messages.append(
compileError(loc(1),
QLatin1String("Invalid version. Version numbers must be >= 0 and < 255.")));
return false;
}
auto version = new (pool) AST::UiVersionSpecifier(major, minor);
version->majorToken = loc(1); version->majorToken = loc(1);
version->minorToken = loc(3); version->minorToken = loc(3);
sym(1).UiVersionSpecifier = version; sym(1).UiVersionSpecifier = version;
} break; } break;
./ ./
UiVersionSpecifier: T_VERSION_NUMBER; UiVersionSpecifier: T_VERSION_NUMBER;
/. /.
case $rule_number: { case $rule_number: {
auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, 0); const int major = sym(1).dval;
if (major < 0 || major >= 255) {
diagnostic_messages.append(
compileError(loc(1),
QLatin1String("Invalid major version. Version numbers must be >= 0 and < 255.")));
return false;
}
auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval);
version->majorToken = loc(1); version->majorToken = loc(1);
sym(1).UiVersionSpecifier = version; sym(1).UiVersionSpecifier = version;
} break; } break;
@@ -1320,6 +1335,7 @@ UiObjectMember: T_DEFAULT UiObjectMemberPropertyNoInitialiser;
} break; } break;
./ ./
UiObjectMember: T_REQUIRED UiObjectMemberListPropertyNoInitialiser; UiObjectMember: T_REQUIRED UiObjectMemberListPropertyNoInitialiser;
/. /.
case $rule_number: { case $rule_number: {
@@ -2277,7 +2293,16 @@ MemberExpression: MemberExpression T_LBRACKET Expression_In T_RBRACKET;
sym(1).Node = node; sym(1).Node = node;
} break; } break;
./ ./
MemberExpression: MemberExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET;
/.
case $rule_number: {
AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression);
node->lbracketToken = loc(3);
node->rbracketToken = loc(5);
node->isOptional = true;
sym(1).Node = node;
} break;
./
-- the identifier has to be "target", catched at codegen time -- the identifier has to be "target", catched at codegen time
NewTarget: T_NEW T_DOT T_IDENTIFIER; NewTarget: T_NEW T_DOT T_IDENTIFIER;
@@ -2300,6 +2325,17 @@ MemberExpression: MemberExpression T_DOT IdentifierName;
} break; } break;
./ ./
MemberExpression: MemberExpression T_QUESTION_DOT IdentifierName;
/.
case $rule_number: {
AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
node->dotToken = loc(2);
node->identifierToken = loc(3);
node->isOptional = true;
sym(1).Node = node;
} break;
./
MemberExpression: MetaProperty; MemberExpression: MetaProperty;
MemberExpression: T_NEW MemberExpression T_LPAREN Arguments T_RPAREN; MemberExpression: T_NEW MemberExpression T_LPAREN Arguments T_RPAREN;
@@ -2348,6 +2384,17 @@ CallExpression: MemberExpression T_LPAREN Arguments T_RPAREN;
} break; } break;
./ ./
CallExpression: MemberExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN;
/.
case $rule_number: {
AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
node->isOptional = true;
sym(1).Node = node;
} break;
./
CallExpression: Super T_LPAREN Arguments T_RPAREN; CallExpression: Super T_LPAREN Arguments T_RPAREN;
/. case $rule_number: Q_FALLTHROUGH(); ./ /. case $rule_number: Q_FALLTHROUGH(); ./
CallExpression: CallExpression T_LPAREN Arguments T_RPAREN; CallExpression: CallExpression T_LPAREN Arguments T_RPAREN;
@@ -2360,6 +2407,18 @@ CallExpression: CallExpression T_LPAREN Arguments T_RPAREN;
} break; } break;
./ ./
CallExpression: CallExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN;
/.
case $rule_number: {
AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList);
node->lparenToken = loc(3);
node->rparenToken = loc(5);
node->isOptional = true;
sym(1).Node = node;
} break;
./
CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET; CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET;
/. /.
case $rule_number: { case $rule_number: {
@@ -2370,6 +2429,17 @@ CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET;
} break; } break;
./ ./
CallExpression: CallExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET;
/.
case $rule_number: {
AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression);
node->lbracketToken = loc(3);
node->rbracketToken = loc(5);
node->isOptional = true;
sym(1).Node = node;
} break;
./
CallExpression: CallExpression T_DOT IdentifierName; CallExpression: CallExpression T_DOT IdentifierName;
/. /.
case $rule_number: { case $rule_number: {
@@ -2380,6 +2450,17 @@ CallExpression: CallExpression T_DOT IdentifierName;
} break; } break;
./ ./
CallExpression: CallExpression T_QUESTION_DOT IdentifierName;
/.
case $rule_number: {
AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
node->dotToken = loc(2);
node->identifierToken = loc(3);
node->isOptional = true;
sym(1).Node = node;
} break;
./
Arguments: ; Arguments: ;
/. /.
case $rule_number: { case $rule_number: {
@@ -2673,6 +2754,12 @@ RelationalOperator: T_INSTANCEOF;
sym(1).ival = QSOperator::InstanceOf; sym(1).ival = QSOperator::InstanceOf;
} break; } break;
./ ./
RelationalOperator: T_AS;
/.
case $rule_number: {
sym(1).ival = QSOperator::As;
} break;
./
RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression; RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
/. /.
@@ -2683,20 +2770,6 @@ RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
} break; } break;
./ ./
TypeAssertExpression_In: RelationalExpression_In T_AS Type;
/. case $rule_number: Q_FALLTHROUGH(); ./
TypeAssertExpression: RelationalExpression T_AS Type;
/.
case $rule_number: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::As, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
./
RelationalExpression_In: TypeAssertExpression_In;
RelationalExpression: TypeAssertExpression;
EqualityExpression_In: RelationalExpression_In; EqualityExpression_In: RelationalExpression_In;
EqualityExpression: RelationalExpression; EqualityExpression: RelationalExpression;
@@ -2873,6 +2946,9 @@ AssignmentExpression: LeftHandSideExpression T_EQ AssignmentExpression;
AssignmentExpression_In: LeftHandSideExpression T_EQ AssignmentExpression_In; AssignmentExpression_In: LeftHandSideExpression T_EQ AssignmentExpression_In;
/. /.
case $rule_number: { case $rule_number: {
if (sym(1).Expression->containsOptionalChain()) {
syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments"));
}
// need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral // need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral
if (AST::Pattern *p = sym(1).Expression->patternCast()) { if (AST::Pattern *p = sym(1).Expression->patternCast()) {
SourceLocation errorLoc; SourceLocation errorLoc;
@@ -2903,6 +2979,9 @@ AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpres
AssignmentExpression_In: LeftHandSideExpression AssignmentOperator AssignmentExpression_In; AssignmentExpression_In: LeftHandSideExpression AssignmentOperator AssignmentExpression_In;
/. /.
case $rule_number: { case $rule_number: {
if (sym(1).Expression->containsOptionalChain()) {
syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments"));
}
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2); node->operatorToken = loc(2);
sym(1).Node = node; sym(1).Node = node;
@@ -4019,15 +4098,14 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpress
/. /.
case $rule_number: { case $rule_number: {
AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression); AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression);
ret->returnToken = sym(4).Node->firstSourceLocation().zeroLength(); ret->returnToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation();
ret->semicolonToken = sym(4).Node->lastSourceLocation().zeroLengthEnd(driver->code()); ret->semicolonToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code());
AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish(); AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish();
AST::FunctionExpression *f = new (pool) AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, statements);
AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, statements);
f->isArrowFunction = true; f->isArrowFunction = true;
f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().zeroLength() : loc(1).zeroLength(); f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation();
f->lbraceToken = sym(4).Node->firstSourceLocation().zeroLength(); f->lbraceToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation();
f->rbraceToken = sym(4).Node->lastSourceLocation().zeroLengthEnd(driver->code()); f->rbraceToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code());
sym(1).Node = f; sym(1).Node = f;
} break; } break;
./ ./
@@ -4039,8 +4117,8 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Fun
case $rule_number: { case $rule_number: {
AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, sym(6).StatementList); AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, sym(6).StatementList);
f->isArrowFunction = true; f->isArrowFunction = true;
f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().zeroLength() : loc(1).zeroLength(); f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation();
f->lbraceToken = loc(5); f->lbraceToken = loc(6);
f->rbraceToken = loc(7); f->rbraceToken = loc(7);
sym(1).Node = f; sym(1).Node = f;
} break; } break;

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -23,11 +23,11 @@
** **
****************************************************************************/ ****************************************************************************/
#include <QLocale>
#include "qmljsast_p.h" #include "qmljsast_p.h"
#include "qmljsastvisitor_p.h" #include "qmljsastvisitor_p.h"
#include <qlocale.h>
#include <QLocale>
QT_QML_BEGIN_NAMESPACE QT_QML_BEGIN_NAMESPACE
@@ -104,6 +104,44 @@ ExpressionNode *ExpressionNode::expressionCast()
return this; return this;
} }
bool ExpressionNode::containsOptionalChain() const
{
for (const Node *node = this;;) {
switch (node->kind) {
case Kind_FieldMemberExpression: {
const auto *fme = AST::cast<const FieldMemberExpression*>(node);
if (fme->isOptional)
return true;
node = fme->base;
break;
}
case Kind_ArrayMemberExpression: {
const auto *ame = AST::cast<const ArrayMemberExpression*>(node);
if (ame->isOptional)
return true;
node = ame->base;
break;
}
case Kind_CallExpression: {
const auto *ce = AST::cast<const CallExpression*>(node);
if (ce->isOptional)
return true;
node = ce->base;
break;
}
case Kind_NestedExpression: {
const auto *ne = AST::cast<const NestedExpression*>(node);
node = ne->expression;
break;
}
default:
// These unhandled nodes lead to invalid lvalues anyway, so they do not need to be handled here.
return false;
}
}
return false;
}
FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *pool) FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *pool)
{ {
AST::ExpressionNode *expr = this; AST::ExpressionNode *expr = this;
@@ -145,6 +183,12 @@ BinaryExpression *BinaryExpression::binaryExpressionCast()
return this; return this;
} }
void TypeExpression::accept0(BaseVisitor *visitor)
{
visitor->visit(this);
visitor->endVisit(this);
}
Statement *Statement::statementCast() Statement *Statement::statementCast()
{ {
return this; return this;
@@ -989,7 +1033,13 @@ BoundNames FormalParameterList::formals() const
// change the name of the earlier argument to enforce the lookup semantics from the spec // change the name of the earlier argument to enforce the lookup semantics from the spec
formals[duplicateIndex].id += QLatin1String("#") + QString::number(i); formals[duplicateIndex].id += QLatin1String("#") + QString::number(i);
} }
formals += {name, it->element->typeAnnotation}; formals += {
name,
it->element->typeAnnotation,
it->element->isInjectedSignalParameter
? BoundName::Injected
: BoundName::Declared
};
} }
++i; ++i;
} }
@@ -1392,7 +1442,8 @@ void PatternElement::boundNames(BoundNames *names)
else if (PatternPropertyList *p = propertyList()) else if (PatternPropertyList *p = propertyList())
p->boundNames(names); p->boundNames(names);
} else { } else {
names->append({bindingIdentifier.toString(), typeAnnotation}); names->append({bindingIdentifier.toString(), typeAnnotation,
isInjectedSignalParameter ? BoundName::Injected : BoundName::Declared});
} }
} }
@@ -1531,7 +1582,7 @@ QString Type::toString() const
void Type::toString(QString *out) const void Type::toString(QString *out) const
{ {
for (QmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) { for (QmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) {
out->append(it->name.toString()); out->append(it->name);
if (it->next) if (it->next)
out->append(QLatin1Char('.')); out->append(QLatin1Char('.'));

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -42,6 +42,7 @@
#include "qmljs/parser/qmljsmemorypool_p.h" #include "qmljs/parser/qmljsmemorypool_p.h"
#include <QtCore/qstring.h> #include <QtCore/qstring.h>
#include <QtCore/qversionnumber.h>
QT_QML_BEGIN_NAMESPACE QT_QML_BEGIN_NAMESPACE
@@ -201,6 +202,7 @@ public:
Kind_SwitchStatement, Kind_SwitchStatement,
Kind_TemplateLiteral, Kind_TemplateLiteral,
Kind_TaggedTemplate, Kind_TaggedTemplate,
Kind_TypeExpression,
Kind_ThisExpression, Kind_ThisExpression,
Kind_ThrowStatement, Kind_ThrowStatement,
Kind_TildeExpression, Kind_TildeExpression,
@@ -319,8 +321,7 @@ public:
QMLJS_DECLARE_AST_NODE(UiQualifiedId) QMLJS_DECLARE_AST_NODE(UiQualifiedId)
UiQualifiedId(QStringView name) UiQualifiedId(QStringView name)
: next(this) : next(this), name(name)
, name(name)
{ kind = K; } { kind = K; }
UiQualifiedId(UiQualifiedId *previous, QStringView name) UiQualifiedId(UiQualifiedId *previous, QStringView name)
@@ -444,6 +445,7 @@ public:
ExpressionNode() {} ExpressionNode() {}
ExpressionNode *expressionCast() override; ExpressionNode *expressionCast() override;
bool containsOptionalChain() const;
AST::FormalParameterList *reparseAsFormalParameterList(MemoryPool *pool); AST::FormalParameterList *reparseAsFormalParameterList(MemoryPool *pool);
@@ -489,6 +491,26 @@ public:
SourceLocation rparenToken; SourceLocation rparenToken;
}; };
class QML_PARSER_EXPORT TypeExpression : public ExpressionNode
{
public:
QMLJS_DECLARE_AST_NODE(TypeExpression)
TypeExpression(Type *t) : m_type(t) { kind = K; }
void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override {
return m_type->firstSourceLocation();
}
SourceLocation lastSourceLocation() const override {
return m_type->lastSourceLocation();
}
Type *m_type;
};
class QML_PARSER_EXPORT ThisExpression: public LeftHandSideExpression class QML_PARSER_EXPORT ThisExpression: public LeftHandSideExpression
{ {
public: public:
@@ -513,11 +535,8 @@ class QML_PARSER_EXPORT IdentifierExpression: public LeftHandSideExpression
public: public:
QMLJS_DECLARE_AST_NODE(IdentifierExpression) QMLJS_DECLARE_AST_NODE(IdentifierExpression)
IdentifierExpression(QStringView n) IdentifierExpression(QStringView n):
: name(n) name (n) { kind = K; }
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -635,7 +654,15 @@ class QML_PARSER_EXPORT UiVersionSpecifier : public Node
public: public:
QMLJS_DECLARE_AST_NODE(UiVersionSpecifier) QMLJS_DECLARE_AST_NODE(UiVersionSpecifier)
UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum) { kind = K; } UiVersionSpecifier(int majorum) : majorVersion(majorum)
{
kind = K;
}
UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum)
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -647,8 +674,8 @@ public:
} }
// attributes: // attributes:
int majorVersion; int majorVersion = -1;
int minorVersion; int minorVersion = -1;
SourceLocation majorToken; SourceLocation majorToken;
SourceLocation minorToken; SourceLocation minorToken;
}; };
@@ -658,11 +685,8 @@ class QML_PARSER_EXPORT StringLiteral : public LeftHandSideExpression
public: public:
QMLJS_DECLARE_AST_NODE(StringLiteral) QMLJS_DECLARE_AST_NODE(StringLiteral)
StringLiteral(QStringView v) StringLiteral(QStringView v):
: value(v) value (v) { kind = K; }
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -683,10 +707,7 @@ public:
QMLJS_DECLARE_AST_NODE(TemplateLiteral) QMLJS_DECLARE_AST_NODE(TemplateLiteral)
TemplateLiteral(QStringView str, QStringView raw, ExpressionNode *e) TemplateLiteral(QStringView str, QStringView raw, ExpressionNode *e)
: value(str) : value(str), rawValue(raw), expression(e), next(nullptr)
, rawValue(raw)
, expression(e)
, next(nullptr)
{ kind = K; } { kind = K; }
SourceLocation firstSourceLocation() const override SourceLocation firstSourceLocation() const override
@@ -712,12 +733,8 @@ class QML_PARSER_EXPORT RegExpLiteral: public LeftHandSideExpression
public: public:
QMLJS_DECLARE_AST_NODE(RegExpLiteral) QMLJS_DECLARE_AST_NODE(RegExpLiteral)
RegExpLiteral(QStringView p, int f) RegExpLiteral(QStringView p, int f):
: pattern(p) pattern (p), flags (f) { kind = K; }
, flags(f)
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -857,13 +874,20 @@ public:
struct QML_PARSER_EXPORT BoundName struct QML_PARSER_EXPORT BoundName
{ {
enum Type {
Declared,
Injected,
};
QString id; QString id;
TypeAnnotation *typeAnnotation = nullptr; Type typeAnnotationType;
BoundName(const QString &id, TypeAnnotation *typeAnnotation) TypeAnnotation *typeAnnotation;
: id(id), typeAnnotation(typeAnnotation) BoundName(const QString &id, TypeAnnotation *typeAnnotation, Type type = Declared)
: id(id), typeAnnotation(typeAnnotation), typeAnnotationType(type)
{} {}
BoundName() = default; BoundName() = default;
QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); } QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); }
bool isInjected() const { return typeAnnotation && typeAnnotationType == Injected; }
}; };
struct BoundNames : public QVector<BoundName> struct BoundNames : public QVector<BoundName>
@@ -907,13 +931,8 @@ public:
: initializer(i), type(t) : initializer(i), type(t)
{ kind = K; } { kind = K; }
PatternElement(QStringView n, PatternElement(QStringView n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding)
TypeAnnotation *typeAnnotation = nullptr, : bindingIdentifier(n), initializer(i), type(t)
ExpressionNode *i = nullptr,
Type t = Binding)
: bindingIdentifier(n)
, initializer(i)
, type(t)
, typeAnnotation(typeAnnotation) , typeAnnotation(typeAnnotation)
{ {
Q_ASSERT(t >= RestElement); Q_ASSERT(t >= RestElement);
@@ -956,6 +975,7 @@ public:
// when used in a VariableDeclarationList // when used in a VariableDeclarationList
VariableScope scope = VariableScope::NoScope; VariableScope scope = VariableScope::NoScope;
bool isForDeclaration = false; bool isForDeclaration = false;
bool isInjectedSignalParameter = false;
}; };
class QML_PARSER_EXPORT PatternElementList : public Node class QML_PARSER_EXPORT PatternElementList : public Node
@@ -1008,8 +1028,7 @@ public:
{ kind = K; } { kind = K; }
PatternProperty(PropertyName *name, QStringView n, ExpressionNode *i = nullptr) PatternProperty(PropertyName *name, QStringView n, ExpressionNode *i = nullptr)
: PatternElement(n, /*type annotation*/ nullptr, i) : PatternElement(n, /*type annotation*/nullptr, i), name(name)
, name(name)
{ kind = K; } { kind = K; }
PatternProperty(PropertyName *name, Pattern *pattern, ExpressionNode *i = nullptr) PatternProperty(PropertyName *name, Pattern *pattern, ExpressionNode *i = nullptr)
@@ -1078,11 +1097,8 @@ class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
public: public:
QMLJS_DECLARE_AST_NODE(IdentifierPropertyName) QMLJS_DECLARE_AST_NODE(IdentifierPropertyName)
IdentifierPropertyName(QStringView n) IdentifierPropertyName(QStringView n):
: id(n) id (n) { kind = K; }
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -1097,11 +1113,8 @@ class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName
public: public:
QMLJS_DECLARE_AST_NODE(StringLiteralPropertyName) QMLJS_DECLARE_AST_NODE(StringLiteralPropertyName)
StringLiteralPropertyName(QStringView n) StringLiteralPropertyName(QStringView n):
: id(n) id (n) { kind = K; }
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -1173,6 +1186,7 @@ public:
ExpressionNode *expression; ExpressionNode *expression;
SourceLocation lbracketToken; SourceLocation lbracketToken;
SourceLocation rbracketToken; SourceLocation rbracketToken;
bool isOptional = false;
}; };
class QML_PARSER_EXPORT FieldMemberExpression: public LeftHandSideExpression class QML_PARSER_EXPORT FieldMemberExpression: public LeftHandSideExpression
@@ -1180,11 +1194,9 @@ class QML_PARSER_EXPORT FieldMemberExpression: public LeftHandSideExpression
public: public:
QMLJS_DECLARE_AST_NODE(FieldMemberExpression) QMLJS_DECLARE_AST_NODE(FieldMemberExpression)
FieldMemberExpression(ExpressionNode *b, QStringView n) FieldMemberExpression(ExpressionNode *b, QStringView n):
: base(b) base (b), name (n)
, name(n) { kind = K; }
{
kind = K; }
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -1199,6 +1211,7 @@ public:
QStringView name; QStringView name;
SourceLocation dotToken; SourceLocation dotToken;
SourceLocation identifierToken; SourceLocation identifierToken;
bool isOptional = false;
}; };
class QML_PARSER_EXPORT TaggedTemplate : public LeftHandSideExpression class QML_PARSER_EXPORT TaggedTemplate : public LeftHandSideExpression
@@ -1291,6 +1304,7 @@ public:
ArgumentList *arguments; ArgumentList *arguments;
SourceLocation lparenToken; SourceLocation lparenToken;
SourceLocation rparenToken; SourceLocation rparenToken;
bool isOptional = false;
}; };
class QML_PARSER_EXPORT ArgumentList: public Node class QML_PARSER_EXPORT ArgumentList: public Node
@@ -1972,11 +1986,8 @@ class QML_PARSER_EXPORT ContinueStatement: public Statement
public: public:
QMLJS_DECLARE_AST_NODE(ContinueStatement) QMLJS_DECLARE_AST_NODE(ContinueStatement)
ContinueStatement(QStringView l = QStringView()) ContinueStatement(QStringView l = QStringView()):
: label(l) label (l) { kind = K; }
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -1998,11 +2009,8 @@ class QML_PARSER_EXPORT BreakStatement: public Statement
public: public:
QMLJS_DECLARE_AST_NODE(BreakStatement) QMLJS_DECLARE_AST_NODE(BreakStatement)
BreakStatement(QStringView l) BreakStatement(QStringView l):
: label(l) label (l) { kind = K; }
{
kind = K;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -2229,11 +2237,9 @@ class QML_PARSER_EXPORT LabelledStatement: public Statement
public: public:
QMLJS_DECLARE_AST_NODE(LabelledStatement) QMLJS_DECLARE_AST_NODE(LabelledStatement)
LabelledStatement(QStringView l, Statement *stmt) LabelledStatement(QStringView l, Statement *stmt):
: label(l) label (l), statement (stmt)
, statement(stmt) { kind = K; }
{
kind = K; }
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -2364,16 +2370,10 @@ class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
public: public:
QMLJS_DECLARE_AST_NODE(FunctionExpression) QMLJS_DECLARE_AST_NODE(FunctionExpression)
FunctionExpression(QStringView n, FunctionExpression(QStringView n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
FormalParameterList *f, name (n), formals (f), body (b),
StatementList *b, typeAnnotation(typeAnnotation)
TypeAnnotation *typeAnnotation = nullptr) { kind = K; }
: name(n)
, formals(f)
, body(b)
, typeAnnotation(typeAnnotation)
{
kind = K; }
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -2405,13 +2405,9 @@ class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
public: public:
QMLJS_DECLARE_AST_NODE(FunctionDeclaration) QMLJS_DECLARE_AST_NODE(FunctionDeclaration)
FunctionDeclaration(QStringView n, FunctionDeclaration(QStringView n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
FormalParameterList *f, FunctionExpression(n, f, b, typeAnnotation)
StatementList *b, { kind = K; }
TypeAnnotation *typeAnnotation = nullptr)
: FunctionExpression(n, f, b, typeAnnotation)
{
kind = K; }
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
}; };
@@ -2507,11 +2503,8 @@ public:
QMLJS_DECLARE_AST_NODE(ClassExpression) QMLJS_DECLARE_AST_NODE(ClassExpression)
ClassExpression(QStringView n, ExpressionNode *heritage, ClassElementList *elements) ClassExpression(QStringView n, ExpressionNode *heritage, ClassElementList *elements)
: name(n) : name(n), heritage(heritage), elements(elements)
, heritage(heritage) { kind = K; }
, elements(elements)
{
kind = K; }
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
@@ -2540,8 +2533,7 @@ public:
ClassDeclaration(QStringView n, ExpressionNode *heritage, ClassElementList *elements) ClassDeclaration(QStringView n, ExpressionNode *heritage, ClassElementList *elements)
: ClassExpression(n, heritage, elements) : ClassExpression(n, heritage, elements)
{ { kind = K; }
kind = K; }
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
}; };
@@ -2617,8 +2609,7 @@ public:
} }
ImportSpecifier(QStringView identifier, QStringView importedBinding) ImportSpecifier(QStringView identifier, QStringView importedBinding)
: identifier(identifier) : identifier(identifier), importedBinding(importedBinding)
, importedBinding(importedBinding)
{ {
kind = K; kind = K;
} }
@@ -2852,15 +2843,13 @@ public:
QMLJS_DECLARE_AST_NODE(ExportSpecifier) QMLJS_DECLARE_AST_NODE(ExportSpecifier)
ExportSpecifier(QStringView identifier) ExportSpecifier(QStringView identifier)
: identifier(identifier) : identifier(identifier), exportedIdentifier(identifier)
, exportedIdentifier(identifier)
{ {
kind = K; kind = K;
} }
ExportSpecifier(QStringView identifier, QStringView exportedIdentifier) ExportSpecifier(QStringView identifier, QStringView exportedIdentifier)
: identifier(identifier) : identifier(identifier), exportedIdentifier(exportedIdentifier)
, exportedIdentifier(exportedIdentifier)
{ {
kind = K; kind = K;
} }
@@ -2959,7 +2948,6 @@ public:
ExportDeclaration(FromClause *fromClause) ExportDeclaration(FromClause *fromClause)
: fromClause(fromClause) : fromClause(fromClause)
{ {
exportAll = true;
kind = K; kind = K;
} }
@@ -2982,6 +2970,11 @@ public:
kind = K; kind = K;
} }
bool exportsAll() const
{
return fromClause && !exportClause;
}
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override SourceLocation firstSourceLocation() const override
@@ -2991,7 +2984,6 @@ public:
// attributes // attributes
SourceLocation exportToken; SourceLocation exportToken;
bool exportAll = false;
ExportClause *exportClause = nullptr; ExportClause *exportClause = nullptr;
FromClause *fromClause = nullptr; FromClause *fromClause = nullptr;
Node *variableStatementOrDeclaration = nullptr; Node *variableStatementOrDeclaration = nullptr;
@@ -3048,8 +3040,7 @@ public:
QMLJS_DECLARE_AST_NODE(UiImport) QMLJS_DECLARE_AST_NODE(UiImport)
UiImport(QStringView fileName) UiImport(QStringView fileName)
: fileName(fileName) : fileName(fileName), importUri(nullptr)
, importUri(nullptr)
{ kind = K; } { kind = K; }
UiImport(UiQualifiedId *uri) UiImport(UiQualifiedId *uri)
@@ -3319,16 +3310,12 @@ class QML_PARSER_EXPORT UiParameterList: public Node
public: public:
QMLJS_DECLARE_AST_NODE(UiParameterList) QMLJS_DECLARE_AST_NODE(UiParameterList)
UiParameterList(UiQualifiedId *t, QStringView n) UiParameterList(UiQualifiedId *t, QStringView n):
: type(t) type (t), name (n), next (this)
, name(n) { kind = K; }
, next(this)
{
kind = K; }
UiParameterList(UiParameterList *previous, UiQualifiedId *t, QStringView n) UiParameterList(UiParameterList *previous, UiQualifiedId *t, QStringView n):
: type(t) type (t), name (n)
, name(n)
{ {
kind = K; kind = K;
next = previous->next; next = previous->next;
@@ -3368,41 +3355,27 @@ class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
public: public:
QMLJS_DECLARE_AST_NODE(UiPublicMember) QMLJS_DECLARE_AST_NODE(UiPublicMember)
UiPublicMember(UiQualifiedId *memberType, QStringView name) UiPublicMember(UiQualifiedId *memberType,
: type(Property) QStringView name)
, memberType(memberType) : type(Property), memberType(memberType), name(name), statement(nullptr), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr)
, name(name)
, statement(nullptr)
, binding(nullptr)
, isDefaultMember(false)
, isReadonlyMember(false)
, parameters(nullptr)
{ kind = K; } { kind = K; }
UiPublicMember(UiQualifiedId *memberType, QStringView name, Statement *statement) UiPublicMember(UiQualifiedId *memberType,
: type(Property) QStringView name,
, memberType(memberType) Statement *statement)
, name(name) : type(Property), memberType(memberType), name(name), statement(statement), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr)
, statement(statement)
, binding(nullptr)
, isDefaultMember(false)
, isReadonlyMember(false)
, parameters(nullptr)
{ kind = K; } { kind = K; }
void accept0(BaseVisitor *visitor) override; void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override SourceLocation firstSourceLocation() const override
{ {
if (requiredToken.isValid()) {
if (defaultToken.isValid() && defaultToken.offset < requiredToken.offset)
return defaultToken;
return requiredToken;
}
if (defaultToken.isValid()) if (defaultToken.isValid())
return defaultToken; return defaultToken;
if (readonlyToken.isValid()) else if (readonlyToken.isValid())
return readonlyToken; return readonlyToken;
else if (requiredToken.isValid())
return requiredToken;
return propertyToken; return propertyToken;
} }
@@ -3469,8 +3442,7 @@ public:
QMLJS_DECLARE_AST_NODE(UiInlineComponent) QMLJS_DECLARE_AST_NODE(UiInlineComponent)
UiInlineComponent(QStringView inlineComponentName, UiObjectDefinition* inlineComponent) UiInlineComponent(QStringView inlineComponentName, UiObjectDefinition* inlineComponent)
: name(inlineComponentName) : name(inlineComponentName), component(inlineComponent)
, component(inlineComponent)
{ kind = K; } { kind = K; }
SourceLocation lastSourceLocation() const override SourceLocation lastSourceLocation() const override
@@ -3596,7 +3568,7 @@ public:
{ kind = K; } { kind = K; }
SourceLocation firstSourceLocation() const override SourceLocation firstSourceLocation() const override
{ return qualifiedId->identifierToken; } { Q_ASSERT(qualifiedId); return qualifiedId->identifierToken; }
SourceLocation lastSourceLocation() const override SourceLocation lastSourceLocation() const override
{ return rbracketToken; } { return rbracketToken; }
@@ -3616,9 +3588,7 @@ class QML_PARSER_EXPORT UiEnumMemberList: public Node
QMLJS_DECLARE_AST_NODE(UiEnumMemberList) QMLJS_DECLARE_AST_NODE(UiEnumMemberList)
public: public:
UiEnumMemberList(QStringView member, double v = 0.0) UiEnumMemberList(QStringView member, double v = 0.0)
: next(this) : next(this), member(member), value(v)
, member(member)
, value(v)
{ kind = K; } { kind = K; }
UiEnumMemberList(UiEnumMemberList *previous, QStringView member) UiEnumMemberList(UiEnumMemberList *previous, QStringView member)
@@ -3631,8 +3601,7 @@ public:
} }
UiEnumMemberList(UiEnumMemberList *previous, QStringView member, double v) UiEnumMemberList(UiEnumMemberList *previous, QStringView member, double v)
: member(member) : member(member), value(v)
, value(v)
{ {
kind = K; kind = K;
next = previous->next; next = previous->next;
@@ -3670,7 +3639,8 @@ class QML_PARSER_EXPORT UiEnumDeclaration: public UiObjectMember
public: public:
QMLJS_DECLARE_AST_NODE(UiEnumDeclaration) QMLJS_DECLARE_AST_NODE(UiEnumDeclaration)
UiEnumDeclaration(QStringView name, UiEnumMemberList *members) UiEnumDeclaration(QStringView name,
UiEnumMemberList *members)
: name(name) : name(name)
, members(members) , members(members)
{ kind = K; } { kind = K; }
@@ -3754,4 +3724,3 @@ public:
QT_QML_END_NAMESPACE QT_QML_END_NAMESPACE

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -50,6 +50,7 @@ class Visitor;
class Node; class Node;
class ExpressionNode; class ExpressionNode;
class Statement; class Statement;
class TypeExpression;
class ThisExpression; class ThisExpression;
class IdentifierExpression; class IdentifierExpression;
class NullExpression; class NullExpression;

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -126,6 +126,9 @@ public:
virtual void endVisit(UiRequired *) = 0; virtual void endVisit(UiRequired *) = 0;
// QmlJS // QmlJS
virtual bool visit(TypeExpression *) = 0;
virtual void endVisit(TypeExpression *) = 0;
virtual bool visit(ThisExpression *) = 0; virtual bool visit(ThisExpression *) = 0;
virtual void endVisit(ThisExpression *) = 0; virtual void endVisit(ThisExpression *) = 0;
@@ -467,6 +470,9 @@ public:
void endVisit(UiRequired *) override {} void endVisit(UiRequired *) override {}
// QmlJS // QmlJS
bool visit(TypeExpression *) override { return true; }
void endVisit(TypeExpression *) override {}
bool visit(ThisExpression *) override { return true; } bool visit(ThisExpression *) override { return true; }
void endVisit(ThisExpression *) override {} void endVisit(ThisExpression *) override {}

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -26,11 +26,9 @@
#include "qmljsengine_p.h" #include "qmljsengine_p.h"
#include "qmljsglobal_p.h" #include "qmljsglobal_p.h"
#include <utils/porting.h>
#include <QtCore/qdebug.h>
#include <QtCore/qhash.h>
#include <QtCore/qnumeric.h> #include <QtCore/qnumeric.h>
#include <QtCore/qhash.h>
#include <QtCore/qdebug.h>
QT_QML_BEGIN_NAMESPACE QT_QML_BEGIN_NAMESPACE
@@ -138,9 +136,7 @@ QStringView Engine::newStringRef(const QString &text)
} }
QStringView Engine::newStringRef(const QChar *chars, int size) QStringView Engine::newStringRef(const QChar *chars, int size)
{ { return newStringRef(QString(chars, size)); }
return newStringRef(QString(chars, size));
}
} // end of namespace QmlJS } // end of namespace QmlJS

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -37,16 +37,14 @@
// //
#include "qmljsglobal_p.h" #include "qmljsglobal_p.h"
#include "qmljs/parser/qmljssourcelocation_p.h"
#include "qmljs/parser/qmljsmemorypool_p.h" #include "qmljs/parser/qmljsmemorypool_p.h"
#include "qmljs/parser/qmljssourcelocation_p.h"
#include <qmljs/qmljsconstants.h>
#include <utils/porting.h>
#include <QString> #include <QString>
#include <QSet> #include <QSet>
#include <qmljs/qmljsconstants.h>
QT_QML_BEGIN_NAMESPACE QT_QML_BEGIN_NAMESPACE
namespace QmlJS { namespace QmlJS {
@@ -107,10 +105,7 @@ public:
MemoryPool *pool(); MemoryPool *pool();
inline QStringView midRef(int position, int size) inline QStringView midRef(int position, int size) { return QStringView{_code}.mid(position, size); }
{
return Utils::midView(_code, position, size);
}
QStringView newStringRef(const QString &s); QStringView newStringRef(const QString &s);
QStringView newStringRef(const QChar *chars, int size); QStringView newStringRef(const QChar *chars, int size);

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -32,23 +32,23 @@ class QML_PARSER_EXPORT QmlJSGrammar
public: public:
enum VariousConstants { enum VariousConstants {
EOF_SYMBOL = 0, EOF_SYMBOL = 0,
REDUCE_HERE = 131, REDUCE_HERE = 132,
T_AND = 1, T_AND = 1,
T_AND_AND = 2, T_AND_AND = 2,
T_AND_EQ = 3, T_AND_EQ = 3,
T_ARROW = 96, T_ARROW = 96,
T_AS = 116, T_AS = 117,
T_AT = 90, T_AT = 90,
T_AUTOMATIC_SEMICOLON = 64, T_AUTOMATIC_SEMICOLON = 64,
T_BREAK = 4, T_BREAK = 4,
T_CASE = 5, T_CASE = 5,
T_CATCH = 6, T_CATCH = 6,
T_CLASS = 102, T_CLASS = 103,
T_COLON = 7, T_COLON = 7,
T_COMMA = 8, T_COMMA = 8,
T_COMMENT = 94, T_COMMENT = 94,
T_COMPATIBILITY_SEMICOLON = 95, T_COMPATIBILITY_SEMICOLON = 95,
T_COMPONENT = 108, T_COMPONENT = 109,
T_CONST = 88, T_CONST = 88,
T_CONTINUE = 9, T_CONTINUE = 9,
T_DEBUGGER = 91, T_DEBUGGER = 91,
@@ -58,32 +58,32 @@ public:
T_DIVIDE_EQ = 13, T_DIVIDE_EQ = 13,
T_DO = 14, T_DO = 14,
T_DOT = 15, T_DOT = 15,
T_ELLIPSIS = 99, T_ELLIPSIS = 100,
T_ELSE = 16, T_ELSE = 16,
T_ENUM = 98, T_ENUM = 99,
T_EQ = 17, T_EQ = 17,
T_EQ_EQ = 18, T_EQ_EQ = 18,
T_EQ_EQ_EQ = 19, T_EQ_EQ_EQ = 19,
T_ERROR = 120, T_ERROR = 121,
T_EXPORT = 105, T_EXPORT = 106,
T_EXTENDS = 103, T_EXTENDS = 104,
T_FALSE = 87, T_FALSE = 87,
T_FEED_JS_EXPRESSION = 124, T_FEED_JS_EXPRESSION = 125,
T_FEED_JS_MODULE = 126, T_FEED_JS_MODULE = 127,
T_FEED_JS_SCRIPT = 125, T_FEED_JS_SCRIPT = 126,
T_FEED_JS_STATEMENT = 123, T_FEED_JS_STATEMENT = 124,
T_FEED_UI_OBJECT_MEMBER = 122, T_FEED_UI_OBJECT_MEMBER = 123,
T_FEED_UI_PROGRAM = 121, T_FEED_UI_PROGRAM = 122,
T_FINALLY = 20, T_FINALLY = 20,
T_FOR = 21, T_FOR = 21,
T_FORCE_BLOCK = 128, T_FORCE_BLOCK = 129,
T_FORCE_DECLARATION = 127, T_FORCE_DECLARATION = 128,
T_FOR_LOOKAHEAD_OK = 129, T_FOR_LOOKAHEAD_OK = 130,
T_FROM = 106, T_FROM = 107,
T_FUNCTION = 23, T_FUNCTION = 23,
T_FUNCTION_STAR = 22, T_FUNCTION_STAR = 22,
T_GE = 24, T_GE = 24,
T_GET = 118, T_GET = 119,
T_GT = 25, T_GT = 25,
T_GT_GT = 26, T_GT_GT = 26,
T_GT_GT_EQ = 27, T_GT_GT_EQ = 27,
@@ -91,7 +91,7 @@ public:
T_GT_GT_GT_EQ = 29, T_GT_GT_GT_EQ = 29,
T_IDENTIFIER = 30, T_IDENTIFIER = 30,
T_IF = 31, T_IF = 31,
T_IMPORT = 114, T_IMPORT = 115,
T_IN = 32, T_IN = 32,
T_INSTANCEOF = 33, T_INSTANCEOF = 33,
T_LBRACE = 34, T_LBRACE = 34,
@@ -110,46 +110,47 @@ public:
T_NOT = 45, T_NOT = 45,
T_NOT_EQ = 46, T_NOT_EQ = 46,
T_NOT_EQ_EQ = 47, T_NOT_EQ_EQ = 47,
T_NO_SUBSTITUTION_TEMPLATE = 109, T_NO_SUBSTITUTION_TEMPLATE = 110,
T_NULL = 85, T_NULL = 85,
T_NUMERIC_LITERAL = 48, T_NUMERIC_LITERAL = 48,
T_OF = 117, T_OF = 118,
T_ON = 130, T_ON = 131,
T_OR = 49, T_OR = 49,
T_OR_EQ = 51, T_OR_EQ = 51,
T_OR_OR = 52, T_OR_OR = 52,
T_PLUS = 53, T_PLUS = 53,
T_PLUS_EQ = 54, T_PLUS_EQ = 54,
T_PLUS_PLUS = 55, T_PLUS_PLUS = 55,
T_PRAGMA = 115, T_PRAGMA = 116,
T_PROPERTY = 70, T_PROPERTY = 70,
T_PUBLIC = 113, T_PUBLIC = 114,
T_QUESTION = 56, T_QUESTION = 56,
T_QUESTION_DOT = 98,
T_QUESTION_QUESTION = 97, T_QUESTION_QUESTION = 97,
T_RBRACE = 57, T_RBRACE = 57,
T_RBRACKET = 58, T_RBRACKET = 58,
T_READONLY = 72, T_READONLY = 72,
T_REMAINDER = 59, T_REMAINDER = 59,
T_REMAINDER_EQ = 60, T_REMAINDER_EQ = 60,
T_REQUIRED = 107, T_REQUIRED = 108,
T_RESERVED_WORD = 92, T_RESERVED_WORD = 92,
T_RETURN = 61, T_RETURN = 61,
T_RPAREN = 62, T_RPAREN = 62,
T_SEMICOLON = 63, T_SEMICOLON = 63,
T_SET = 119, T_SET = 120,
T_SIGNAL = 71, T_SIGNAL = 71,
T_STAR = 65, T_STAR = 65,
T_STAR_EQ = 68, T_STAR_EQ = 68,
T_STAR_STAR = 66, T_STAR_STAR = 66,
T_STAR_STAR_EQ = 67, T_STAR_STAR_EQ = 67,
T_STATIC = 104, T_STATIC = 105,
T_STRING_LITERAL = 69, T_STRING_LITERAL = 69,
T_SUPER = 101, T_SUPER = 102,
T_SWITCH = 73, T_SWITCH = 73,
T_TEMPLATE_HEAD = 110, T_TEMPLATE_HEAD = 111,
T_TEMPLATE_MIDDLE = 111, T_TEMPLATE_MIDDLE = 112,
T_TEMPLATE_TAIL = 112, T_TEMPLATE_TAIL = 113,
T_THEN = 132, T_THEN = 133,
T_THIS = 74, T_THIS = 74,
T_THROW = 75, T_THROW = 75,
T_TILDE = 76, T_TILDE = 76,
@@ -161,20 +162,20 @@ public:
T_VOID = 80, T_VOID = 80,
T_WHILE = 81, T_WHILE = 81,
T_WITH = 82, T_WITH = 82,
T_WITHOUTAS = 133, T_WITHOUTAS = 134,
T_XOR = 83, T_XOR = 83,
T_XOR_EQ = 84, T_XOR_EQ = 84,
T_YIELD = 100, T_YIELD = 101,
ACCEPT_STATE = 1102, ACCEPT_STATE = 1114,
RULE_COUNT = 619, RULE_COUNT = 622,
STATE_COUNT = 1103, STATE_COUNT = 1115,
TERMINAL_COUNT = 134, TERMINAL_COUNT = 135,
NON_TERMINAL_COUNT = 238, NON_TERMINAL_COUNT = 236,
GOTO_INDEX_OFFSET = 1103, GOTO_INDEX_OFFSET = 1115,
GOTO_INFO_OFFSET = 6857, GOTO_INFO_OFFSET = 7121,
GOTO_CHECK_OFFSET = 6857 GOTO_CHECK_OFFSET = 7121
}; };
static const char *const spell[]; static const char *const spell[];
@@ -214,4 +215,3 @@ public:
#endif // QMLJSGRAMMAR_P_H #endif // QMLJSGRAMMAR_P_H

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -43,8 +43,6 @@ Q_CORE_EXPORT double qstrntod(const char *s00, qsizetype len, char const **se, b
#endif #endif
QT_END_NAMESPACE QT_END_NAMESPACE
QT_QML_BEGIN_NAMESPACE
using namespace QmlJS; using namespace QmlJS;
static inline int regExpFlagFromChar(const QChar &ch) static inline int regExpFlagFromChar(const QChar &ch)
@@ -79,7 +77,7 @@ Lexer::Lexer(Engine *engine)
, _codePtr(nullptr) , _codePtr(nullptr)
, _endPtr(nullptr) , _endPtr(nullptr)
, _tokenStartPtr(nullptr) , _tokenStartPtr(nullptr)
, _char(QLatin1Char('\n')) , _char(u'\n')
, _errorCode(NoError) , _errorCode(NoError)
, _currentLineNumber(0) , _currentLineNumber(0)
, _currentColumnNumber(0) , _currentColumnNumber(0)
@@ -131,7 +129,7 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
_endPtr = _codePtr + code.length(); _endPtr = _codePtr + code.length();
_tokenStartPtr = _codePtr; _tokenStartPtr = _codePtr;
_char = QLatin1Char('\n'); _char = u'\n';
_errorCode = NoError; _errorCode = NoError;
_currentLineNumber = lineno; _currentLineNumber = lineno;
@@ -160,7 +158,7 @@ void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
void Lexer::scanChar() void Lexer::scanChar()
{ {
if (_skipLinefeed) { if (_skipLinefeed) {
Q_ASSERT(*_codePtr == QLatin1Char('\n')); Q_ASSERT(*_codePtr == u'\n');
++_codePtr; ++_codePtr;
_skipLinefeed = false; _skipLinefeed = false;
} }
@@ -168,16 +166,24 @@ void Lexer::scanChar()
++_currentColumnNumber; ++_currentColumnNumber;
if (isLineTerminator()) { if (isLineTerminator()) {
if (_char == QLatin1Char('\r')) { if (_char == u'\r') {
if (_codePtr < _endPtr && *_codePtr == QLatin1Char('\n')) if (_codePtr < _endPtr && *_codePtr == u'\n')
_skipLinefeed = true; _skipLinefeed = true;
_char = QLatin1Char('\n'); _char = u'\n';
} }
++_currentLineNumber; ++_currentLineNumber;
_currentColumnNumber = 0; _currentColumnNumber = 0;
} }
} }
QChar Lexer::peekChar()
{
auto peekPtr = _codePtr;
if (peekPtr < _endPtr)
return *peekPtr;
return QChar();
}
namespace { namespace {
inline bool isBinop(int tok) inline bool isBinop(int tok)
{ {
@@ -225,19 +231,19 @@ inline bool isBinop(int tok)
int hexDigit(QChar c) int hexDigit(QChar c)
{ {
if (c >= QLatin1Char('0') && c <= QLatin1Char('9')) if (c >= u'0' && c <= u'9')
return c.unicode() - '0'; return c.unicode() - u'0';
if (c >= QLatin1Char('a') && c <= QLatin1Char('f')) if (c >= u'a' && c <= u'f')
return c.unicode() - 'a' + 10; return c.unicode() - u'a' + 10;
if (c >= QLatin1Char('A') && c <= QLatin1Char('F')) if (c >= u'A' && c <= u'F')
return c.unicode() - 'A' + 10; return c.unicode() - u'A' + 10;
return -1; return -1;
} }
int octalDigit(QChar c) int octalDigit(QChar c)
{ {
if (c >= QLatin1Char('0') && c <= QLatin1Char('7')) if (c >= u'0' && c <= u'7')
return c.unicode() - '0'; return c.unicode() - u'0';
return -1; return -1;
} }
@@ -340,7 +346,7 @@ int Lexer::lex()
uint Lexer::decodeUnicodeEscapeCharacter(bool *ok) uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
{ {
Q_ASSERT(_char == QLatin1Char('u')); Q_ASSERT(_char == u'u');
scanChar(); // skip u scanChar(); // skip u
if (_codePtr + 4 <= _endPtr && isHexDigit(_char)) { if (_codePtr + 4 <= _endPtr && isHexDigit(_char)) {
uint codePoint = 0; uint codePoint = 0;
@@ -355,7 +361,7 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
*ok = true; *ok = true;
return codePoint; return codePoint;
} else if (_codePtr < _endPtr && _char == QLatin1Char('{')) { } else if (_codePtr < _endPtr && _char == u'{') {
scanChar(); // skip '{' scanChar(); // skip '{'
uint codePoint = 0; uint codePoint = 0;
if (!isHexDigit(_char)) if (!isHexDigit(_char))
@@ -373,7 +379,7 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
scanChar(); scanChar();
} }
if (_char != QLatin1Char('}')) if (_char != u'}')
goto error; goto error;
scanChar(); // skip '}' scanChar(); // skip '}'
@@ -415,9 +421,9 @@ QChar Lexer::decodeHexEscapeCharacter(bool *ok)
static inline bool isIdentifierStart(uint ch) static inline bool isIdentifierStart(uint ch)
{ {
// fast path for ascii // fast path for ascii
if ((ch >= 'a' && ch <= 'z') || if ((ch >= u'a' && ch <= u'z') ||
(ch >= 'A' && ch <= 'Z') || (ch >= u'A' && ch <= u'Z') ||
ch == '$' || ch == '_') ch == u'$' || ch == u'_')
return true; return true;
switch (QChar::category(ch)) { switch (QChar::category(ch)) {
@@ -437,10 +443,10 @@ static inline bool isIdentifierStart(uint ch)
static bool isIdentifierPart(uint ch) static bool isIdentifierPart(uint ch)
{ {
// fast path for ascii // fast path for ascii
if ((ch >= 'a' && ch <= 'z') || if ((ch >= u'a' && ch <= u'z') ||
(ch >= 'A' && ch <= 'Z') || (ch >= u'A' && ch <= u'Z') ||
(ch >= '0' && ch <= '9') || (ch >= u'0' && ch <= u'9') ||
ch == '$' || ch == '_' || ch == u'$' || ch == u'_' ||
ch == 0x200c /* ZWNJ */ || ch == 0x200d /* ZWJ */) ch == 0x200c /* ZWNJ */ || ch == 0x200d /* ZWJ */)
return true; return true;
@@ -487,12 +493,12 @@ again:
// handle comment can be called after a '/' has been read // handle comment can be called after a '/' has been read
// and returns true if it actually encountered a comment // and returns true if it actually encountered a comment
auto handleComment = [this](){ auto handleComment = [this](){
if (_char == QLatin1Char('*')) { if (_char == u'*') {
scanChar(); scanChar();
while (_codePtr <= _endPtr) { while (_codePtr <= _endPtr) {
if (_char == QLatin1Char('*')) { if (_char == u'*') {
scanChar(); scanChar();
if (_char == QLatin1Char('/')) { if (_char == u'/') {
scanChar(); scanChar();
if (_engine) { if (_engine) {
@@ -506,7 +512,7 @@ again:
scanChar(); scanChar();
} }
} }
} else if (_char == QLatin1Char('/')) { } else if (_char == u'/') {
while (_codePtr <= _endPtr && !isLineTerminator()) { while (_codePtr <= _endPtr && !isLineTerminator()) {
scanChar(); scanChar();
} }
@@ -548,81 +554,85 @@ again:
scanChar(); scanChar();
switch (ch.unicode()) { switch (ch.unicode()) {
case '~': return T_TILDE; case u'~': return T_TILDE;
case '}': return T_RBRACE; case u'}': return T_RBRACE;
case '|': case u'|':
if (_char == QLatin1Char('|')) { if (_char == u'|') {
scanChar(); scanChar();
return T_OR_OR; return T_OR_OR;
} else if (_char == QLatin1Char('=')) { } else if (_char == u'=') {
scanChar(); scanChar();
return T_OR_EQ; return T_OR_EQ;
} }
return T_OR; return T_OR;
case '{': return T_LBRACE; case u'{': return T_LBRACE;
case '^': case u'^':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_XOR_EQ; return T_XOR_EQ;
} }
return T_XOR; return T_XOR;
case ']': return T_RBRACKET; case u']': return T_RBRACKET;
case '[': return T_LBRACKET; case u'[': return T_LBRACKET;
case '?': { case u'?': {
if (_char == QLatin1Char('?')) { if (_char == u'?') {
scanChar(); scanChar();
return T_QUESTION_QUESTION; return T_QUESTION_QUESTION;
} }
if (_char == u'.' && !peekChar().isDigit()) {
scanChar();
return T_QUESTION_DOT;
}
return T_QUESTION; return T_QUESTION;
} }
case '>': case u'>':
if (_char == QLatin1Char('>')) { if (_char == u'>') {
scanChar(); scanChar();
if (_char == QLatin1Char('>')) { if (_char == u'>') {
scanChar(); scanChar();
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_GT_GT_GT_EQ; return T_GT_GT_GT_EQ;
} }
return T_GT_GT_GT; return T_GT_GT_GT;
} else if (_char == QLatin1Char('=')) { } else if (_char == u'=') {
scanChar(); scanChar();
return T_GT_GT_EQ; return T_GT_GT_EQ;
} }
return T_GT_GT; return T_GT_GT;
} else if (_char == QLatin1Char('=')) { } else if (_char == u'=') {
scanChar(); scanChar();
return T_GE; return T_GE;
} }
return T_GT; return T_GT;
case '=': case u'=':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_EQ_EQ_EQ; return T_EQ_EQ_EQ;
} }
return T_EQ_EQ; return T_EQ_EQ;
} else if (_char == QLatin1Char('>')) { } else if (_char == u'>') {
scanChar(); scanChar();
return T_ARROW; return T_ARROW;
} }
return T_EQ; return T_EQ;
case '<': case u'<':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_LE; return T_LE;
} else if (_char == QLatin1Char('<')) { } else if (_char == u'<') {
scanChar(); scanChar();
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_LT_LT_EQ; return T_LT_LT_EQ;
} }
@@ -630,26 +640,26 @@ again:
} }
return T_LT; return T_LT;
case ';': return T_SEMICOLON; case u';': return T_SEMICOLON;
case ':': return T_COLON; case u':': return T_COLON;
case '/': case u'/':
if (handleComment()) if (handleComment())
goto again; goto again;
else if (_char == QLatin1Char('=')) { else if (_char == u'=') {
scanChar(); scanChar();
return T_DIVIDE_EQ; return T_DIVIDE_EQ;
} }
return T_DIVIDE_; return T_DIVIDE_;
case '.': case u'.':
if (_importState == ImportState::SawImport) if (_importState == ImportState::SawImport)
return T_DOT; return T_DOT;
if (isDecimalDigit(_char.unicode())) if (isDecimalDigit(_char.unicode()))
return scanNumber(ch); return scanNumber(ch);
if (_char == QLatin1Char('.')) { if (_char == u'.') {
scanChar(); scanChar();
if (_char == QLatin1Char('.')) { if (_char == u'.') {
scanChar(); scanChar();
return T_ELLIPSIS; return T_ELLIPSIS;
} else { } else {
@@ -660,11 +670,11 @@ again:
} }
return T_DOT; return T_DOT;
case '-': case u'-':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_MINUS_EQ; return T_MINUS_EQ;
} else if (_char == QLatin1Char('-')) { } else if (_char == u'-') {
scanChar(); scanChar();
if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) { if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
@@ -676,13 +686,13 @@ again:
} }
return T_MINUS; return T_MINUS;
case ',': return T_COMMA; case u',': return T_COMMA;
case '+': case u'+':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_PLUS_EQ; return T_PLUS_EQ;
} else if (_char == QLatin1Char('+')) { } else if (_char == u'+') {
scanChar(); scanChar();
if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) { if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
@@ -694,13 +704,13 @@ again:
} }
return T_PLUS; return T_PLUS;
case '*': case u'*':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_STAR_EQ; return T_STAR_EQ;
} else if (_char == QLatin1Char('*')) { } else if (_char == u'*') {
scanChar(); scanChar();
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_STAR_STAR_EQ; return T_STAR_STAR_EQ;
} }
@@ -708,32 +718,32 @@ again:
} }
return T_STAR; return T_STAR;
case ')': return T_RPAREN; case u')': return T_RPAREN;
case '(': return T_LPAREN; case u'(': return T_LPAREN;
case '@': return T_AT; case u'@': return T_AT;
case '&': case u'&':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_AND_EQ; return T_AND_EQ;
} else if (_char == QLatin1Char('&')) { } else if (_char == u'&') {
scanChar(); scanChar();
return T_AND_AND; return T_AND_AND;
} }
return T_AND; return T_AND;
case '%': case u'%':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_REMAINDER_EQ; return T_REMAINDER_EQ;
} }
return T_REMAINDER; return T_REMAINDER;
case '!': case u'!':
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
if (_char == QLatin1Char('=')) { if (_char == u'=') {
scanChar(); scanChar();
return T_NOT_EQ_EQ; return T_NOT_EQ_EQ;
} }
@@ -741,34 +751,48 @@ again:
} }
return T_NOT; return T_NOT;
case '`': case u'`':
_outerTemplateBraceCount.push(_bracesCount); _outerTemplateBraceCount.push(_bracesCount);
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case '\'': case u'\'':
case '"': case u'"':
return scanString(ScanStringMode(ch.unicode())); return scanString(ScanStringMode(ch.unicode()));
case '0': case u'0':
case '1': case u'1':
case '2': case u'2':
case '3': case u'3':
case '4': case u'4':
case '5': case u'5':
case '6': case u'6':
case '7': case u'7':
case '8': case u'8':
case '9': case u'9':
if (_importState == ImportState::SawImport) if (_importState == ImportState::SawImport)
return scanVersionNumber(ch); return scanVersionNumber(ch);
else else
return scanNumber(ch); return scanNumber(ch);
case '#':
if (_currentLineNumber == 1 && _currentColumnNumber == 2) {
// shebang support
while (_codePtr <= _endPtr && !isLineTerminator()) {
scanChar();
}
if (_engine) {
_engine->addComment(tokenOffset(), _codePtr - _tokenStartPtr - 1,
tokenStartLine(), tokenStartColumn());
}
goto again;
}
Q_FALLTHROUGH();
default: { default: {
uint c = ch.unicode(); uint c = ch.unicode();
bool identifierWithEscapeChars = false; bool identifierWithEscapeChars = false;
if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_char.unicode())) { if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_char.unicode())) {
c = QChar::surrogateToUcs4(ushort(c), _char.unicode()); c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
scanChar(); scanChar();
} else if (c == '\\' && _char == QLatin1Char('u')) { } else if (c == '\\' && _char == u'u') {
identifierWithEscapeChars = true; identifierWithEscapeChars = true;
bool ok = false; bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok); c = decodeUnicodeEscapeCharacter(&ok);
@@ -791,7 +815,7 @@ again:
if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_codePtr->unicode())) { if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_codePtr->unicode())) {
scanChar(); scanChar();
c = QChar::surrogateToUcs4(ushort(c), _char.unicode()); c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
} else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) { } else if (_char == u'\\' && _codePtr[0] == u'u') {
if (!identifierWithEscapeChars) { if (!identifierWithEscapeChars) {
identifierWithEscapeChars = true; identifierWithEscapeChars = true;
_tokenText.resize(0); _tokenText.resize(0);
@@ -808,14 +832,12 @@ again:
if (!isIdentifierPart(c)) if (!isIdentifierPart(c))
break; break;
if (identifierWithEscapeChars) {
if (QChar::requiresSurrogates(c)) { if (QChar::requiresSurrogates(c)) {
_tokenText += QChar(QChar::highSurrogate(c)); _tokenText += QChar(QChar::highSurrogate(c));
_tokenText += QChar(QChar::lowSurrogate(c)); _tokenText += QChar(QChar::lowSurrogate(c));
} else { } else {
_tokenText += QChar(c); _tokenText += QChar(c);
} }
}
continue; continue;
} }
@@ -844,11 +866,11 @@ again:
continue_skipping: continue_skipping:
while (_codePtr < _endPtr && _char.isSpace()) while (_codePtr < _endPtr && _char.isSpace())
scanChar(); scanChar();
if (_char == QLatin1Char('*')) { if (_char == u'*') {
_tokenLength = _codePtr - _tokenStartPtr - 1; _tokenLength = _codePtr - _tokenStartPtr - 1;
kind = T_FUNCTION_STAR; kind = T_FUNCTION_STAR;
scanChar(); scanChar();
} else if (_char == QLatin1Char('/')) { } else if (_char == u'/') {
scanChar(); scanChar();
if (handleComment()) if (handleComment())
goto continue_skipping; goto continue_skipping;
@@ -882,27 +904,28 @@ int Lexer::scanString(ScanStringMode mode)
// correctly in the loop below and afterwards // correctly in the loop below and afterwards
_skipLinefeed = false; _skipLinefeed = false;
bool first = true; bool first = true;
if (_engine) { if (_engine) {
while (_codePtr <= _endPtr) { while (_codePtr <= _endPtr) {
if (isLineTerminator()) { if (isLineTerminator()) {
if ((quote == QLatin1Char('`') || qmlMode())) { if ((quote == u'`' || qmlMode())) {
if (first) if (first)
--_currentLineNumber; --_currentLineNumber; // will be read again in scanChar()
break; break;
} }
_errorCode = IllegalCharacter; _errorCode = IllegalCharacter;
_errorMessage = QCoreApplication::translate("QmlParser", "Stray newline in string literal"); _errorMessage = QCoreApplication::translate("QmlParser", "Stray newline in string literal");
return T_ERROR; return T_ERROR;
} else if (_char == QLatin1Char('\\')) { } else if (_char == u'\\') {
break; break;
} else if (_char == '$' && quote == QLatin1Char('`')) { } else if (_char == u'$' && quote == u'`') {
break; break;
} else if (_char == quote) { } else if (_char == quote) {
_tokenSpell = _engine->midRef(startCode - _code.unicode(), _codePtr - startCode - 1); _tokenSpell = _engine->midRef(startCode - _code.unicode(), _codePtr - startCode - 1);
_rawString = _tokenSpell; _rawString = _tokenSpell;
scanChar(); scanChar();
if (quote == QLatin1Char('`')) if (quote == u'`')
_bracesCount = _outerTemplateBraceCount.pop(); _bracesCount = _outerTemplateBraceCount.pop();
if (mode == TemplateHead) if (mode == TemplateHead)
@@ -929,7 +952,7 @@ int Lexer::scanString(ScanStringMode mode)
auto setRawString = [&](const QChar *end) { auto setRawString = [&](const QChar *end) {
QString raw(startCode, end - startCode - 1); QString raw(startCode, end - startCode - 1);
raw.replace(QLatin1String("\r\n"), QLatin1String("\n")); raw.replace(QLatin1String("\r\n"), QLatin1String("\n"));
raw.replace(QLatin1Char('\r'), QLatin1Char('\n')); raw.replace(u'\r', u'\n');
_rawString = _engine->newStringRef(raw); _rawString = _engine->newStringRef(raw);
}; };
@@ -941,11 +964,11 @@ int Lexer::scanString(ScanStringMode mode)
if (_engine) { if (_engine) {
_tokenSpell = _engine->newStringRef(_tokenText); _tokenSpell = _engine->newStringRef(_tokenText);
if (quote == QLatin1Char('`')) if (quote == u'`')
setRawString(_codePtr - 1); setRawString(_codePtr - 1);
} }
if (quote == QLatin1Char('`')) if (quote == u'`')
_bracesCount = _outerTemplateBraceCount.pop(); _bracesCount = _outerTemplateBraceCount.pop();
if (mode == TemplateContinuation) if (mode == TemplateContinuation)
@@ -954,7 +977,7 @@ int Lexer::scanString(ScanStringMode mode)
return T_NO_SUBSTITUTION_TEMPLATE; return T_NO_SUBSTITUTION_TEMPLATE;
return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL; return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
} else if (quote == QLatin1Char('`') && _char == QLatin1Char('$') && *_codePtr == '{') { } else if (quote == u'`' && _char == u'$' && *_codePtr == u'{') {
scanChar(); scanChar();
scanChar(); scanChar();
_bracesCount = 1; _bracesCount = 1;
@@ -964,7 +987,7 @@ int Lexer::scanString(ScanStringMode mode)
} }
return (mode == TemplateHead ? T_TEMPLATE_HEAD : T_TEMPLATE_MIDDLE); return (mode == TemplateHead ? T_TEMPLATE_HEAD : T_TEMPLATE_MIDDLE);
} else if (_char == QLatin1Char('\\')) { } else if (_char == u'\\') {
scanChar(); scanChar();
if (_codePtr > _endPtr) { if (_codePtr > _endPtr) {
_errorCode = IllegalEscapeSequence; _errorCode = IllegalEscapeSequence;
@@ -976,7 +999,7 @@ int Lexer::scanString(ScanStringMode mode)
switch (_char.unicode()) { switch (_char.unicode()) {
// unicode escape sequence // unicode escape sequence
case 'u': { case u'u': {
bool ok = false; bool ok = false;
uint codePoint = decodeUnicodeEscapeCharacter(&ok); uint codePoint = decodeUnicodeEscapeCharacter(&ok);
if (!ok) if (!ok)
@@ -991,7 +1014,7 @@ int Lexer::scanString(ScanStringMode mode)
} break; } break;
// hex escape sequence // hex escape sequence
case 'x': { case u'x': {
bool ok = false; bool ok = false;
u = decodeHexEscapeCharacter(&ok); u = decodeHexEscapeCharacter(&ok);
if (!ok) { if (!ok) {
@@ -1002,38 +1025,38 @@ int Lexer::scanString(ScanStringMode mode)
} break; } break;
// single character escape sequence // single character escape sequence
case '\\': u = QLatin1Char('\\'); scanChar(); break; case u'\\': u = u'\\'; scanChar(); break;
case '\'': u = QLatin1Char('\''); scanChar(); break; case u'\'': u = u'\''; scanChar(); break;
case '\"': u = QLatin1Char('\"'); scanChar(); break; case u'\"': u = u'\"'; scanChar(); break;
case 'b': u = QLatin1Char('\b'); scanChar(); break; case u'b': u = u'\b'; scanChar(); break;
case 'f': u = QLatin1Char('\f'); scanChar(); break; case u'f': u = u'\f'; scanChar(); break;
case 'n': u = QLatin1Char('\n'); scanChar(); break; case u'n': u = u'\n'; scanChar(); break;
case 'r': u = QLatin1Char('\r'); scanChar(); break; case u'r': u = u'\r'; scanChar(); break;
case 't': u = QLatin1Char('\t'); scanChar(); break; case u't': u = u'\t'; scanChar(); break;
case 'v': u = QLatin1Char('\v'); scanChar(); break; case u'v': u = u'\v'; scanChar(); break;
case '0': case u'0':
if (! _codePtr->isDigit()) { if (! _codePtr->isDigit()) {
scanChar(); scanChar();
u = QLatin1Char('\0'); u = u'\0';
break; break;
} }
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case '1': case u'1':
case '2': case u'2':
case '3': case u'3':
case '4': case u'4':
case '5': case u'5':
case '6': case u'6':
case '7': case u'7':
case '8': case u'8':
case '9': case u'9':
_errorCode = IllegalEscapeSequence; _errorCode = IllegalEscapeSequence;
_errorMessage = QCoreApplication::translate("QmlParser", "Octal escape sequences are not allowed"); _errorMessage = QCoreApplication::translate("QmlParser", "Octal escape sequences are not allowed");
return T_ERROR; return T_ERROR;
case '\r': case u'\r':
case '\n': case u'\n':
case 0x2028u: case 0x2028u:
case 0x2029u: case 0x2029u:
scanChar(); scanChar();
@@ -1059,8 +1082,8 @@ int Lexer::scanString(ScanStringMode mode)
int Lexer::scanNumber(QChar ch) int Lexer::scanNumber(QChar ch)
{ {
if (ch == QLatin1Char('0')) { if (ch == u'0') {
if (_char == QLatin1Char('x') || _char == QLatin1Char('X')) { if (_char == u'x' || _char == u'X') {
ch = _char; // remember the x or X to use it in the error message below. ch = _char; // remember the x or X to use it in the error message below.
// parse hex integer literal // parse hex integer literal
@@ -1084,7 +1107,7 @@ int Lexer::scanNumber(QChar ch)
_tokenValue = d; _tokenValue = d;
return T_NUMERIC_LITERAL; return T_NUMERIC_LITERAL;
} else if (_char == QLatin1Char('o') || _char == QLatin1Char('O')) { } else if (_char == u'o' || _char == u'O') {
ch = _char; // remember the o or O to use it in the error message below. ch = _char; // remember the o or O to use it in the error message below.
// parse octal integer literal // parse octal integer literal
@@ -1108,13 +1131,13 @@ int Lexer::scanNumber(QChar ch)
_tokenValue = d; _tokenValue = d;
return T_NUMERIC_LITERAL; return T_NUMERIC_LITERAL;
} else if (_char == QLatin1Char('b') || _char == QLatin1Char('B')) { } else if (_char == u'b' || _char == u'B') {
ch = _char; // remember the b or B to use it in the error message below. ch = _char; // remember the b or B to use it in the error message below.
// parse binary integer literal // parse binary integer literal
scanChar(); // consume 'b' scanChar(); // consume 'b'
if (_char.unicode() != '0' && _char.unicode() != '1') { if (_char.unicode() != u'0' && _char.unicode() != u'1') {
_errorCode = IllegalNumber; _errorCode = IllegalNumber;
_errorMessage = QCoreApplication::translate("QmlParser", "At least one binary digit is required after '0%1'").arg(ch); _errorMessage = QCoreApplication::translate("QmlParser", "At least one binary digit is required after '0%1'").arg(ch);
return T_ERROR; return T_ERROR;
@@ -1123,9 +1146,9 @@ int Lexer::scanNumber(QChar ch)
double d = 0.; double d = 0.;
while (1) { while (1) {
int digit = 0; int digit = 0;
if (_char.unicode() == '1') if (_char.unicode() == u'1')
digit = 1; digit = 1;
else if (_char.unicode() != '0') else if (_char.unicode() != u'0')
break; break;
d *= 2; d *= 2;
d += digit; d += digit;
@@ -1145,13 +1168,13 @@ int Lexer::scanNumber(QChar ch)
QVarLengthArray<char,32> chars; QVarLengthArray<char,32> chars;
chars.append(ch.unicode()); chars.append(ch.unicode());
if (ch != QLatin1Char('.')) { if (ch != u'.') {
while (_char.isDigit()) { while (_char.isDigit()) {
chars.append(_char.unicode()); chars.append(_char.unicode());
scanChar(); // consume the digit scanChar(); // consume the digit
} }
if (_char == QLatin1Char('.')) { if (_char == u'.') {
chars.append(_char.unicode()); chars.append(_char.unicode());
scanChar(); // consume `.' scanChar(); // consume `.'
} }
@@ -1162,14 +1185,14 @@ int Lexer::scanNumber(QChar ch)
scanChar(); scanChar();
} }
if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) { if (_char == u'e' || _char == u'E') {
if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) && if (_codePtr[0].isDigit() || ((_codePtr[0] == u'+' || _codePtr[0] == u'-') &&
_codePtr[1].isDigit())) { _codePtr[1].isDigit())) {
chars.append(_char.unicode()); chars.append(_char.unicode());
scanChar(); // consume `e' scanChar(); // consume `e'
if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) { if (_char == u'+' || _char == u'-') {
chars.append(_char.unicode()); chars.append(_char.unicode());
scanChar(); // consume the sign scanChar(); // consume the sign
} }
@@ -1198,7 +1221,7 @@ int Lexer::scanNumber(QChar ch)
int Lexer::scanVersionNumber(QChar ch) int Lexer::scanVersionNumber(QChar ch)
{ {
if (ch == QLatin1Char('0')) { if (ch == u'0') {
_tokenValue = 0; _tokenValue = 0;
return T_VERSION_NUMBER; return T_VERSION_NUMBER;
} }
@@ -1223,11 +1246,11 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
_patternFlags = 0; _patternFlags = 0;
if (prefix == EqualPrefix) if (prefix == EqualPrefix)
_tokenText += QLatin1Char('='); _tokenText += u'=';
while (true) { while (true) {
switch (_char.unicode()) { switch (_char.unicode()) {
case '/': case u'/':
scanChar(); scanChar();
// scan the flags // scan the flags
@@ -1246,7 +1269,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
_tokenLength = _codePtr - _tokenStartPtr - 1; _tokenLength = _codePtr - _tokenStartPtr - 1;
return true; return true;
case '\\': case u'\\':
// regular expression backslash sequence // regular expression backslash sequence
_tokenText += _char; _tokenText += _char;
scanChar(); scanChar();
@@ -1260,15 +1283,15 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
scanChar(); scanChar();
break; break;
case '[': case u'[':
// regular expression class // regular expression class
_tokenText += _char; _tokenText += _char;
scanChar(); scanChar();
while (_codePtr <= _endPtr && ! isLineTerminator()) { while (_codePtr <= _endPtr && ! isLineTerminator()) {
if (_char == QLatin1Char(']')) if (_char == u']')
break; break;
else if (_char == QLatin1Char('\\')) { else if (_char == u'\\') {
// regular expression backslash sequence // regular expression backslash sequence
_tokenText += _char; _tokenText += _char;
scanChar(); scanChar();
@@ -1286,7 +1309,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
} }
} }
if (_char != QLatin1Char(']')) { if (_char != u']') {
_errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression class"); _errorMessage = QCoreApplication::translate("QmlParser", "Unterminated regular expression class");
return false; return false;
} }
@@ -1339,10 +1362,9 @@ bool Lexer::isIdentLetter(QChar ch)
{ {
// ASCII-biased, since all reserved words are ASCII, aand hence the // ASCII-biased, since all reserved words are ASCII, aand hence the
// bulk of content to be parsed. // bulk of content to be parsed.
if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) if ((ch >= u'a' && ch <= u'z')
|| (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z')) || (ch >= u'A' && ch <= u'Z')
|| ch == QLatin1Char('$') || ch == u'$' || ch == u'_')
|| ch == QLatin1Char('_'))
return true; return true;
if (ch.unicode() < 128) if (ch.unicode() < 128)
return false; return false;
@@ -1351,19 +1373,19 @@ bool Lexer::isIdentLetter(QChar ch)
bool Lexer::isDecimalDigit(ushort c) bool Lexer::isDecimalDigit(ushort c)
{ {
return (c >= '0' && c <= '9'); return (c >= u'0' && c <= u'9');
} }
bool Lexer::isHexDigit(QChar c) bool Lexer::isHexDigit(QChar c)
{ {
return ((c >= QLatin1Char('0') && c <= QLatin1Char('9')) return ((c >= u'0' && c <= u'9')
|| (c >= QLatin1Char('a') && c <= QLatin1Char('f')) || (c >= u'a' && c <= u'f')
|| (c >= QLatin1Char('A') && c <= QLatin1Char('F'))); || (c >= u'A' && c <= u'F'));
} }
bool Lexer::isOctalDigit(ushort c) bool Lexer::isOctalDigit(ushort c)
{ {
return (c >= '0' && c <= '7'); return (c >= u'0' && c <= u'7');
} }
QString Lexer::tokenText() const QString Lexer::tokenText() const
@@ -1533,9 +1555,10 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
setError(QCoreApplication::translate("QmlParser","Imported file must be a script")); setError(QCoreApplication::translate("QmlParser","Imported file must be a script"));
return false; return false;
} }
lex();
} else if (_tokenKind == T_IDENTIFIER) { } else if (_tokenKind == T_IDENTIFIER) {
// .import T_IDENTIFIER (. T_IDENTIFIER)* T_VERSION_NUMBER . T_VERSION_NUMBER as T_IDENTIFIER // .import T_IDENTIFIER (. T_IDENTIFIER)* (T_VERSION_NUMBER (. T_VERSION_NUMBER)?)? as T_IDENTIFIER
while (true) { while (true) {
if (!isUriToken(_tokenKind)) { if (!isUriToken(_tokenKind)) {
setError(QCoreApplication::translate("QmlParser","Invalid module URI")); setError(QCoreApplication::translate("QmlParser","Invalid module URI"));
@@ -1552,7 +1575,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
if (_tokenKind != QmlJSGrammar::T_DOT) if (_tokenKind != QmlJSGrammar::T_DOT)
break; break;
pathOrUri.append(QLatin1Char('.')); pathOrUri.append(u'.');
lex(); lex();
if (tokenStartLine() != lineNumber) { if (tokenStartLine() != lineNumber) {
@@ -1561,31 +1584,27 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
} }
} }
if (_tokenKind != T_VERSION_NUMBER) { if (_tokenKind == T_VERSION_NUMBER) {
setError(QCoreApplication::translate("QmlParser","Module import requires a version"));
return false; // expected the module version number
}
version = tokenText(); version = tokenText();
lex(); lex();
if (_tokenKind != T_DOT) { if (_tokenKind == T_DOT) {
setError(QCoreApplication::translate( "QmlParser", "Module import requires a minor version (missing dot)")); version += u'.';
return false; // expected the module version number
}
version += QLatin1Char('.');
lex(); lex();
if (_tokenKind != T_VERSION_NUMBER) { if (_tokenKind != T_VERSION_NUMBER) {
setError(QCoreApplication::translate( "QmlParser", "Module import requires a minor version (missing number)")); setError(QCoreApplication::translate(
"QmlParser", "Incomplete version number (dot but no minor)"));
return false; // expected the module version number return false; // expected the module version number
} }
version += tokenText(); version += tokenText();
lex();
}
}
} }
// //
// recognize the mandatory `as' followed by the module name // recognize the mandatory `as' followed by the module name
// //
if (! (lex() == T_AS && tokenStartLine() == lineNumber)) { if (! (_tokenKind == T_AS && tokenStartLine() == lineNumber)) {
if (fileImport) if (fileImport)
setError(QCoreApplication::translate("QmlParser", "File import requires a qualifier")); setError(QCoreApplication::translate("QmlParser", "File import requires a qualifier"));
else else
@@ -1628,5 +1647,3 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
return true; return true;
} }
QT_QML_END_NAMESPACE

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -176,6 +176,7 @@ protected:
private: private:
inline void scanChar(); inline void scanChar();
inline QChar peekChar();
int scanToken(); int scanToken();
int scanNumber(QChar ch); int scanNumber(QChar ch);
int scanVersionNumber(QChar ch); int scanVersionNumber(QChar ch);

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -90,8 +90,7 @@ public:
template <typename Tp, typename... Ta> Tp *New(Ta... args) template <typename Tp, typename... Ta> Tp *New(Ta... args)
{ return new (this->allocate(sizeof(Tp))) Tp(args...); } { return new (this->allocate(sizeof(Tp))) Tp(args...); }
QStringView newString(const QString &string) QStringView newString(const QString &string) {
{
strings.append(new QString(string)); strings.append(new QString(string));
return QStringView(*strings.last()); return QStringView(*strings.last());
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,6 @@
#line 185 "qmljs.g"
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -292,27 +290,27 @@ protected:
#line 1862 "qmljs.g" #line 1878 "qmljs.g"
#define J_SCRIPT_REGEXPLITERAL_RULE1 164 #define J_SCRIPT_REGEXPLITERAL_RULE1 164
#line 1874 "qmljs.g" #line 1890 "qmljs.g"
#define J_SCRIPT_REGEXPLITERAL_RULE2 165 #define J_SCRIPT_REGEXPLITERAL_RULE2 165
#line 3423 "qmljs.g" #line 3502 "qmljs.g"
#define J_SCRIPT_EXPRESSIONSTATEMENTLOOKAHEAD_RULE 463 #define J_SCRIPT_EXPRESSIONSTATEMENTLOOKAHEAD_RULE 466
#line 4076 "qmljs.g" #line 4154 "qmljs.g"
#define J_SCRIPT_CONCISEBODYLOOKAHEAD_RULE 533 #define J_SCRIPT_CONCISEBODYLOOKAHEAD_RULE 536
#line 4618 "qmljs.g" #line 4696 "qmljs.g"
#define J_SCRIPT_EXPORTDECLARATIONLOOKAHEAD_RULE 602 #define J_SCRIPT_EXPORTDECLARATIONLOOKAHEAD_RULE 605
#line 4902 "qmljs.g" #line 4980 "qmljs.g"
QT_QML_END_NAMESPACE QT_QML_END_NAMESPACE

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -26,8 +26,7 @@
#pragma once #pragma once
#include "qmljsglobal_p.h" #include "qmljsglobal_p.h"
#include <QtCore/qhashfunctions.h>
#include <QtCore/QStringView>
// //
// W A R N I N G // W A R N I N G
@@ -52,13 +51,19 @@ public:
startLine(line), startColumn(column) startLine(line), startColumn(column)
{ } { }
bool isValid() const { return length != 0; } bool isValid() const { return *this != SourceLocation(); }
quint32 begin() const { return offset; } quint32 begin() const { return offset; }
quint32 end() const { return offset + length; } quint32 end() const { return offset + length; }
SourceLocation zeroLength() const { return SourceLocation(offset, 0, startLine, startColumn); } // Returns a zero length location at the start of the current one.
SourceLocation zeroLengthEnd(QStringView text) const { SourceLocation startZeroLengthLocation() const
{
return SourceLocation(offset, 0, startLine, startColumn);
}
// Returns a zero length location at the end of the current one.
SourceLocation endZeroLengthLocation(QStringView text) const
{
quint32 i = offset; quint32 i = offset;
quint32 endLine = startLine; quint32 endLine = startLine;
quint32 endColumn = startColumn; quint32 endColumn = startColumn;
@@ -71,7 +76,7 @@ public:
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case '\r': case '\r':
++endLine; ++endLine;
++endColumn; endColumn = 1;
break; break;
default: default:
++endColumn; ++endColumn;
@@ -87,6 +92,33 @@ public:
quint32 length; quint32 length;
quint32 startLine; quint32 startLine;
quint32 startColumn; quint32 startColumn;
friend size_t qHash(const SourceLocation &location, size_t seed = 0)
{
return (seed ^ (size_t(location.offset) << 8) ^ size_t(location.length)
^ (size_t(location.startLine) << 16) ^ (size_t(location.startColumn) << 24));
}
friend bool operator==(const SourceLocation &a, const SourceLocation &b)
{
return a.offset == b.offset && a.length == b.length && a.startLine == b.startLine
&& a.startColumn == b.startColumn;
}
friend bool operator!=(const SourceLocation &a, const SourceLocation &b) { return !(a == b); }
// Returns a source location starting at the beginning of l1, l2 and ending at the end of them.
// Ignores invalid source locations.
friend SourceLocation combine(const SourceLocation &l1, const SourceLocation &l2) {
quint32 e = qMax(l1.end(), l2.end());
SourceLocation res;
if (l1.offset <= l2.offset)
res = (l1.isValid() ? l1 : l2);
else
res = (l2.isValid() ? l2 : l1);
res.length = e - res.offset;
return res;
}
}; };
} // namespace QmlJS } // namespace QmlJS

View File

@@ -60,6 +60,7 @@ Project {
prefix: "parser/" prefix: "parser/"
files: [ files: [
"qmldirparser.cpp", "qmldirparser_p.h", "qmldirparser.cpp", "qmldirparser_p.h",
"qmlimportresolver.cpp", "qmlimportresolver_p.h",
"qmljsast.cpp", "qmljsast_p.h", "qmljsast.cpp", "qmljsast_p.h",
"qmljsastfwd_p.h", "qmljsastfwd_p.h",
"qmljsastvisitor.cpp", "qmljsastvisitor_p.h", "qmljsastvisitor.cpp", "qmljsastvisitor_p.h",

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.

View File

@@ -370,7 +370,7 @@ LibraryInfo::LibraryInfo(Status status)
updateFingerprint(); updateFingerprint();
} }
LibraryInfo::LibraryInfo(const QmlDirParser::TypeInfo &typeInfo) LibraryInfo::LibraryInfo(const QString &typeInfo)
: _status(Found) : _status(Found)
{ {
_typeinfos.append(typeInfo); _typeinfos.append(typeInfo);
@@ -421,10 +421,10 @@ QByteArray LibraryInfo::calculateFingerprint() const
} }
len = _typeinfos.size(); len = _typeinfos.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
foreach (const QmlDirParser::TypeInfo &typeinfo, _typeinfos) { foreach (const QString &typeinfo, _typeinfos) {
len = typeinfo.fileName.size(); len = typeinfo.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
hash.addData(reinterpret_cast<const char *>(typeinfo.fileName.constData()), hash.addData(reinterpret_cast<const char *>(typeinfo.constData()),
len * sizeofQChar); len * sizeofQChar);
} }
len = _metaObjects.size(); len = _metaObjects.size();

View File

@@ -153,7 +153,7 @@ private:
Status _status = NotScanned; Status _status = NotScanned;
QList<QmlDirParser::Component> _components; QList<QmlDirParser::Component> _components;
QList<QmlDirParser::Plugin> _plugins; QList<QmlDirParser::Plugin> _plugins;
QList<QmlDirParser::TypeInfo> _typeinfos; QStringList _typeinfos;
typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList; typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList;
FakeMetaObjectList _metaObjects; FakeMetaObjectList _metaObjects;
QList<ModuleApiInfo> _moduleApis; QList<ModuleApiInfo> _moduleApis;
@@ -167,7 +167,7 @@ private:
public: public:
LibraryInfo(); LibraryInfo();
explicit LibraryInfo(Status status); explicit LibraryInfo(Status status);
explicit LibraryInfo(const QmlDirParser::TypeInfo &typeInfo); explicit LibraryInfo(const QString &typeInfo);
explicit LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerprint = QByteArray()); explicit LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerprint = QByteArray());
~LibraryInfo() = default; ~LibraryInfo() = default;
LibraryInfo(const LibraryInfo &other) = default; LibraryInfo(const LibraryInfo &other) = default;
@@ -183,7 +183,7 @@ public:
QList<QmlDirParser::Plugin> plugins() const QList<QmlDirParser::Plugin> plugins() const
{ return _plugins; } { return _plugins; }
QList<QmlDirParser::TypeInfo> typeInfos() const QStringList typeInfos() const
{ return _typeinfos; } { return _typeinfos; }
FakeMetaObjectList metaObjects() const FakeMetaObjectList metaObjects() const

View File

@@ -811,7 +811,7 @@ static bool findNewQmlApplicationInPath(const QString &path,
qmltypesFile = it.next(); qmltypesFile = it.next();
LibraryInfo libraryInfo = LibraryInfo(QmlDirParser::TypeInfo(qmltypesFile)); LibraryInfo libraryInfo = LibraryInfo(qmltypesFile);
const QString libraryPath = dir.absolutePath(); const QString libraryPath = dir.absolutePath();
newLibraries->insert(libraryPath); newLibraries->insert(libraryPath);
modelManager->updateLibraryInfo(path, libraryInfo); modelManager->updateLibraryInfo(path, libraryInfo);

View File

@@ -154,8 +154,8 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString &
} }
// add typeinfo files listed in qmldir // add typeinfo files listed in qmldir
foreach (const QmlDirParser::TypeInfo &typeInfo, libraryInfo.typeInfos()) { foreach (const QString &typeInfo, libraryInfo.typeInfos()) {
QString pathNow = makeAbsolute(typeInfo.fileName, canonicalLibraryPath); QString pathNow = makeAbsolute(typeInfo, canonicalLibraryPath);
if (!plugin.typeInfoPaths.contains(pathNow) && QFile::exists(pathNow)) if (!plugin.typeInfoPaths.contains(pathNow) && QFile::exists(pathNow))
plugin.typeInfoPaths += pathNow; plugin.typeInfoPaths += pathNow;
} }

View File

@@ -209,7 +209,7 @@ const QString undefinedVersion = QLatin1String("-1.-1");
* undefined version (-1.-1) or if it is empty. False otherwise. * undefined version (-1.-1) or if it is empty. False otherwise.
*/ */
bool QmlJS::maybeModuleVersion(const QString &version) { bool QmlJS::maybeModuleVersion(const QString &version) {
QRegularExpression re(QLatin1String("^\\d+\\.\\d+$")); QRegularExpression re(QLatin1String("^\\d+\\.-?\\d+$"));
return version.isEmpty() || version == undefinedVersion || re.match(version).hasMatch(); return version.isEmpty() || version == undefinedVersion || re.match(version).hasMatch();
} }