forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/qmlprojectstorage'
Conflicts: src/plugins/qmldesigner/qmldesignerprojectmanager.cpp src/plugins/qmlprojectmanager/qmlproject.cpp src/plugins/qmlprojectmanager/qmlproject.h Change-Id: I0c0d59c8e3b8455b6ac575d34fdf49f39388db7a Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
341
share/qtcreator/qmldesigner/projectstorage/fake.qmltypes
Normal file
341
share/qtcreator/qmldesigner/projectstorage/fake.qmltypes
Normal file
@@ -0,0 +1,341 @@
|
||||
import QtQuick.tooling 1.2
|
||||
|
||||
|
||||
Module {
|
||||
|
||||
Component {
|
||||
name: "Qt3DAnimation::QAnimationClipData"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVector<float>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVector<qreal>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVector<int>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVector<QRgb>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVector<uchar>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "uint"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QGeometryView"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QMatrix3x3"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "Qt3DRender::QLevelOfDetailBoundingSphere"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QImage"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "qlonglong"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "qulonglong"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "Hits"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QAbstractTexture"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QBrush"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QDeclarativeListProperty<QGraphicsObject>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QLocale"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QPen"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QGraphicsLayout"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QGraphicsEffect"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QGraphicsLayout"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QPalette"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QRegExp"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QRegExp"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QColor>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QAudioDevice>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QAudioDevice>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QMediaMetaData>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QGeoCoordinate>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QLinearGradient>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QCameraFormat>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QCameraDevice>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QAbstractState*>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QMatrix4x4>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QScxmlError>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QScxmlInvokableService*>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QUrl>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QRgb>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<uchar>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QString>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<QPolygonF>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QList<int>"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QCameraFormat"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "Features"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVideoSink"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVideoSink*"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVideoFrameFormat::PixelFormat"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QV4::ExecutionEngine"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QSizePolicy"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QLinearGradient"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "const QObject"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QPlatformDialogHelper::StandardButtons"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QPlatformDialogHelper::ButtonRole"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QScene2D::RenderPolicy"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QPlatformDialogHelper::ButtonLayout"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "Keyboard_QMLTYPE_22"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "ShadowInputControl_QMLTYPE_16"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "ShadowInputControl_QMLTYPE_16"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "const QPointingDevice"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QQuickHandlerPoint"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QQuick3DBounds3"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QPointingDevice::DeviceTypes"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "TextureChannelMapping"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "MorphTargetAttributes"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QQuick3DRenderStats"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QScxmlDataModel"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QTapReading::TapDirection"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QAmbientLightReading::LightLevel"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QQuickWebEngineScriptCollection"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QQuickWebEngineScriptCollection"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QOrientationReading::Orientation"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QScxmlCompiler::Loader"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QScxmlTableData"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QFileDialogOptions::FileDialogOptions"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QFontDialogOptions::FontDialogOptions"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "ApplicationInterface"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QSortFilterProxyModel"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QIfAmFmTunerStation"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QOpcUaLocalizedText"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QDate"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "Qt::InputMethodHints"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QChar"
|
||||
}
|
||||
|
||||
Component {
|
||||
name: "QVector3D"
|
||||
}
|
||||
}
|
9770
src/libs/3rdparty/sqlite/sqlite3.c
vendored
9770
src/libs/3rdparty/sqlite/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
378
src/libs/3rdparty/sqlite/sqlite3.h
vendored
378
src/libs/3rdparty/sqlite/sqlite3.h
vendored
@@ -146,9 +146,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.37.2"
|
||||
#define SQLITE_VERSION_NUMBER 3037002
|
||||
#define SQLITE_SOURCE_ID "2022-01-06 13:25:41 872ba256cbf61d9290b571c0e6d82a20c224ca3ad82971edc46b29818d5d17a0"
|
||||
#define SQLITE_VERSION "3.38.3"
|
||||
#define SQLITE_VERSION_NUMBER 3038003
|
||||
#define SQLITE_SOURCE_ID "2022-04-27 12:03:15 9547e2c38a1c6f751a77d4d796894dec4dc5d8f5d79b1cd39e1ffc50df7b3be4"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@@ -566,7 +566,7 @@ SQLITE_API int sqlite3_exec(
|
||||
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
|
||||
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
|
||||
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags For File Open Operations
|
||||
@@ -3824,13 +3824,14 @@ SQLITE_API void sqlite3_free_filename(char*);
|
||||
** sqlite3_extended_errcode() might change with each API call.
|
||||
** Except, there are some interfaces that are guaranteed to never
|
||||
** change the value of the error code. The error-code preserving
|
||||
** interfaces are:
|
||||
** interfaces include the following:
|
||||
**
|
||||
** <ul>
|
||||
** <li> sqlite3_errcode()
|
||||
** <li> sqlite3_extended_errcode()
|
||||
** <li> sqlite3_errmsg()
|
||||
** <li> sqlite3_errmsg16()
|
||||
** <li> sqlite3_error_offset()
|
||||
** </ul>
|
||||
**
|
||||
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
|
||||
@@ -3845,6 +3846,13 @@ SQLITE_API void sqlite3_free_filename(char*);
|
||||
** ^(Memory to hold the error message string is managed internally
|
||||
** and must not be freed by the application)^.
|
||||
**
|
||||
** ^If the most recent error references a specific token in the input
|
||||
** SQL, the sqlite3_error_offset() interface returns the byte offset
|
||||
** of the start of that token. ^The byte offset returned by
|
||||
** sqlite3_error_offset() assumes that the input SQL is UTF8.
|
||||
** ^If the most recent error does not reference a specific token in the input
|
||||
** SQL, then the sqlite3_error_offset() function returns -1.
|
||||
**
|
||||
** When the serialized [threading mode] is in use, it might be the
|
||||
** case that a second error occurs on a separate thread in between
|
||||
** the time of the first error and the call to these interfaces.
|
||||
@@ -3864,6 +3872,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
|
||||
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
|
||||
SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
|
||||
SQLITE_API const char *sqlite3_errstr(int);
|
||||
SQLITE_API int sqlite3_error_offset(sqlite3 *db);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Object
|
||||
@@ -4275,6 +4284,10 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
||||
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
|
||||
** read-only no-op if the table already exists, but
|
||||
** sqlite3_stmt_readonly() still returns false for such a statement.
|
||||
**
|
||||
** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN]
|
||||
** statement, then sqlite3_stmt_readonly(X) returns the same value as
|
||||
** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted.
|
||||
*/
|
||||
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||
|
||||
@@ -4343,6 +4356,8 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
||||
**
|
||||
** ^The sqlite3_value objects that are passed as parameters into the
|
||||
** implementation of [application-defined SQL functions] are protected.
|
||||
** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()]
|
||||
** are protected.
|
||||
** ^The sqlite3_value object returned by
|
||||
** [sqlite3_column_value()] is unprotected.
|
||||
** Unprotected sqlite3_value objects may only be used as arguments
|
||||
@@ -4964,6 +4979,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
** even empty strings, are always zero-terminated. ^The return
|
||||
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
|
||||
**
|
||||
** ^Strings returned by sqlite3_column_text16() always have the endianness
|
||||
** which is native to the platform, regardless of the text encoding set
|
||||
** for the database.
|
||||
**
|
||||
** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
|
||||
** [unprotected sqlite3_value] object. In a multithreaded environment,
|
||||
** an unprotected sqlite3_value object may only be used safely with
|
||||
@@ -4977,7 +4996,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
** [application-defined SQL functions] or [virtual tables], not within
|
||||
** top-level application code.
|
||||
**
|
||||
** The these routines may attempt to convert the datatype of the result.
|
||||
** These routines may attempt to convert the datatype of the result.
|
||||
** ^For example, if the internal representation is FLOAT and a text result
|
||||
** is requested, [sqlite3_snprintf()] is used internally to perform the
|
||||
** conversion automatically. ^(The following table details the conversions
|
||||
@@ -5002,7 +5021,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
** <tr><td> TEXT <td> BLOB <td> No change
|
||||
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
|
||||
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
|
||||
** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
|
||||
** <tr><td> BLOB <td> TEXT <td> [CAST] to TEXT, ensure zero terminator
|
||||
** </table>
|
||||
** </blockquote>)^
|
||||
**
|
||||
@@ -7122,24 +7141,56 @@ struct sqlite3_index_info {
|
||||
**
|
||||
** These macros define the allowed values for the
|
||||
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
||||
** an operator that is part of a constraint term in the wHERE clause of
|
||||
** an operator that is part of a constraint term in the WHERE clause of
|
||||
** a query that uses a [virtual table].
|
||||
**
|
||||
** ^The left-hand operand of the operator is given by the corresponding
|
||||
** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand
|
||||
** operand is the rowid.
|
||||
** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET
|
||||
** operators have no left-hand operand, and so for those operators the
|
||||
** corresponding aConstraint[].iColumn is meaningless and should not be
|
||||
** used.
|
||||
**
|
||||
** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through
|
||||
** value 255 are reserved to represent functions that are overloaded
|
||||
** by the [xFindFunction|xFindFunction method] of the virtual table
|
||||
** implementation.
|
||||
**
|
||||
** The right-hand operands for each constraint might be accessible using
|
||||
** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand
|
||||
** operand is only available if it appears as a single constant literal
|
||||
** in the input SQL. If the right-hand operand is another column or an
|
||||
** expression (even a constant expression) or a parameter, then the
|
||||
** sqlite3_vtab_rhs_value() probably will not be able to extract it.
|
||||
** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and
|
||||
** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand
|
||||
** and hence calls to sqlite3_vtab_rhs_value() for those operators will
|
||||
** always return SQLITE_NOTFOUND.
|
||||
**
|
||||
** The collating sequence to be used for comparison can be found using
|
||||
** the [sqlite3_vtab_collation()] interface. For most real-world virtual
|
||||
** tables, the collating sequence of constraints does not matter (for example
|
||||
** because the constraints are numeric) and so the sqlite3_vtab_collation()
|
||||
** interface is no commonly needed.
|
||||
*/
|
||||
#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
||||
#define SQLITE_INDEX_CONSTRAINT_GT 4
|
||||
#define SQLITE_INDEX_CONSTRAINT_LE 8
|
||||
#define SQLITE_INDEX_CONSTRAINT_LT 16
|
||||
#define SQLITE_INDEX_CONSTRAINT_GE 32
|
||||
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
|
||||
#define SQLITE_INDEX_CONSTRAINT_LIKE 65
|
||||
#define SQLITE_INDEX_CONSTRAINT_GLOB 66
|
||||
#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
|
||||
#define SQLITE_INDEX_CONSTRAINT_NE 68
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
||||
#define SQLITE_INDEX_CONSTRAINT_IS 72
|
||||
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
||||
#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
||||
#define SQLITE_INDEX_CONSTRAINT_GT 4
|
||||
#define SQLITE_INDEX_CONSTRAINT_LE 8
|
||||
#define SQLITE_INDEX_CONSTRAINT_LT 16
|
||||
#define SQLITE_INDEX_CONSTRAINT_GE 32
|
||||
#define SQLITE_INDEX_CONSTRAINT_MATCH 64
|
||||
#define SQLITE_INDEX_CONSTRAINT_LIKE 65
|
||||
#define SQLITE_INDEX_CONSTRAINT_GLOB 66
|
||||
#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
|
||||
#define SQLITE_INDEX_CONSTRAINT_NE 68
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
||||
#define SQLITE_INDEX_CONSTRAINT_IS 72
|
||||
#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
|
||||
#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
|
||||
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
||||
|
||||
/*
|
||||
** CAPI3REF: Register A Virtual Table Implementation
|
||||
@@ -7168,7 +7219,7 @@ struct sqlite3_index_info {
|
||||
** destructor.
|
||||
**
|
||||
** ^If the third parameter (the pointer to the sqlite3_module object) is
|
||||
** NULL then no new module is create and any existing modules with the
|
||||
** NULL then no new module is created and any existing modules with the
|
||||
** same name are dropped.
|
||||
**
|
||||
** See also: [sqlite3_drop_modules()]
|
||||
@@ -7944,7 +7995,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_SEEK_COUNT 30
|
||||
#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
||||
#define SQLITE_TESTCTRL_TUNE 32
|
||||
#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */
|
||||
#define SQLITE_TESTCTRL_LOGEST 33
|
||||
#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Keyword Checking
|
||||
@@ -8467,6 +8519,16 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
** The counter is incremented on the first [sqlite3_step()] call of each
|
||||
** cycle.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_FILTER_MISS]]
|
||||
** [[SQLITE_STMTSTATUS_FILTER HIT]]
|
||||
** <dt>SQLITE_STMTSTATUS_FILTER_HIT<br>
|
||||
** SQLITE_STMTSTATUS_FILTER_MISS</dt>
|
||||
** <dd>^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join
|
||||
** step was bypassed because a Bloom filter returned not-found. The
|
||||
** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
|
||||
** times that the Bloom filter returned a find, and thus the join step
|
||||
** had to be processed as normal.
|
||||
**
|
||||
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
||||
** <dd>^This is the approximate number of bytes of heap memory
|
||||
** used to store the prepared statement. ^This value is not actually
|
||||
@@ -8481,6 +8543,8 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
#define SQLITE_STMTSTATUS_VM_STEP 4
|
||||
#define SQLITE_STMTSTATUS_REPREPARE 5
|
||||
#define SQLITE_STMTSTATUS_RUN 6
|
||||
#define SQLITE_STMTSTATUS_FILTER_MISS 7
|
||||
#define SQLITE_STMTSTATUS_FILTER_HIT 8
|
||||
#define SQLITE_STMTSTATUS_MEMUSED 99
|
||||
|
||||
/*
|
||||
@@ -9449,19 +9513,269 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
|
||||
** METHOD: sqlite3_index_info
|
||||
**
|
||||
** This function may only be called from within a call to the [xBestIndex]
|
||||
** method of a [virtual table].
|
||||
** method of a [virtual table]. This function returns a pointer to a string
|
||||
** that is the name of the appropriate collation sequence to use for text
|
||||
** comparisons on the constraint identified by its arguments.
|
||||
**
|
||||
** The first argument must be the sqlite3_index_info object that is the
|
||||
** first parameter to the xBestIndex() method. The second argument must be
|
||||
** an index into the aConstraint[] array belonging to the sqlite3_index_info
|
||||
** structure passed to xBestIndex. This function returns a pointer to a buffer
|
||||
** containing the name of the collation sequence for the corresponding
|
||||
** constraint.
|
||||
** The first argument must be the pointer to the [sqlite3_index_info] object
|
||||
** that is the first parameter to the xBestIndex() method. The second argument
|
||||
** must be an index into the aConstraint[] array belonging to the
|
||||
** sqlite3_index_info structure passed to xBestIndex.
|
||||
**
|
||||
** Important:
|
||||
** The first parameter must be the same pointer that is passed into the
|
||||
** xBestMethod() method. The first parameter may not be a pointer to a
|
||||
** different [sqlite3_index_info] object, even an exact copy.
|
||||
**
|
||||
** The return value is computed as follows:
|
||||
**
|
||||
** <ol>
|
||||
** <li><p> If the constraint comes from a WHERE clause expression that contains
|
||||
** a [COLLATE operator], then the name of the collation specified by
|
||||
** that COLLATE operator is returned.
|
||||
** <li><p> If there is no COLLATE operator, but the column that is the subject
|
||||
** of the constraint specifies an alternative collating sequence via
|
||||
** a [COLLATE clause] on the column definition within the CREATE TABLE
|
||||
** statement that was passed into [sqlite3_declare_vtab()], then the
|
||||
** name of that alternative collating sequence is returned.
|
||||
** <li><p> Otherwise, "BINARY" is returned.
|
||||
** </ol>
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine if a virtual table query is DISTINCT
|
||||
** METHOD: sqlite3_index_info
|
||||
**
|
||||
** This API may only be used from within an [xBestIndex|xBestIndex method]
|
||||
** of a [virtual table] implementation. The result of calling this
|
||||
** interface from outside of xBestIndex() is undefined and probably harmful.
|
||||
**
|
||||
** ^The sqlite3_vtab_distinct() interface returns an integer that is
|
||||
** either 0, 1, or 2. The integer returned by sqlite3_vtab_distinct()
|
||||
** gives the virtual table additional information about how the query
|
||||
** planner wants the output to be ordered. As long as the virtual table
|
||||
** can meet the ordering requirements of the query planner, it may set
|
||||
** the "orderByConsumed" flag.
|
||||
**
|
||||
** <ol><li value="0"><p>
|
||||
** ^If the sqlite3_vtab_distinct() interface returns 0, that means
|
||||
** that the query planner needs the virtual table to return all rows in the
|
||||
** sort order defined by the "nOrderBy" and "aOrderBy" fields of the
|
||||
** [sqlite3_index_info] object. This is the default expectation. If the
|
||||
** virtual table outputs all rows in sorted order, then it is always safe for
|
||||
** the xBestIndex method to set the "orderByConsumed" flag, regardless of
|
||||
** the return value from sqlite3_vtab_distinct().
|
||||
** <li value="1"><p>
|
||||
** ^(If the sqlite3_vtab_distinct() interface returns 1, that means
|
||||
** that the query planner does not need the rows to be returned in sorted order
|
||||
** as long as all rows with the same values in all columns identified by the
|
||||
** "aOrderBy" field are adjacent.)^ This mode is used when the query planner
|
||||
** is doing a GROUP BY.
|
||||
** <li value="2"><p>
|
||||
** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
|
||||
** that the query planner does not need the rows returned in any particular
|
||||
** order, as long as rows with the same values in all "aOrderBy" columns
|
||||
** are adjacent.)^ ^(Furthermore, only a single row for each particular
|
||||
** combination of values in the columns identified by the "aOrderBy" field
|
||||
** needs to be returned.)^ ^It is always ok for two or more rows with the same
|
||||
** values in all "aOrderBy" columns to be returned, as long as all such rows
|
||||
** are adjacent. ^The virtual table may, if it chooses, omit extra rows
|
||||
** that have the same value for all columns identified by "aOrderBy".
|
||||
** ^However omitting the extra rows is optional.
|
||||
** This mode is used for a DISTINCT query.
|
||||
** </ol>
|
||||
**
|
||||
** ^For the purposes of comparing virtual table output values to see if the
|
||||
** values are same value for sorting purposes, two NULL values are considered
|
||||
** to be the same. In other words, the comparison operator is "IS"
|
||||
** (or "IS NOT DISTINCT FROM") and not "==".
|
||||
**
|
||||
** If a virtual table implementation is unable to meet the requirements
|
||||
** specified above, then it must not set the "orderByConsumed" flag in the
|
||||
** [sqlite3_index_info] object or an incorrect answer may result.
|
||||
**
|
||||
** ^A virtual table implementation is always free to return rows in any order
|
||||
** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
||||
** the "orderByConsumed" flag is unset, the query planner will add extra
|
||||
** [bytecode] to ensure that the final results returned by the SQL query are
|
||||
** ordered correctly. The use of the "orderByConsumed" flag and the
|
||||
** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
||||
** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed"
|
||||
** flag might help queries against a virtual table to run faster. Being
|
||||
** overly aggressive and setting the "orderByConsumed" flag when it is not
|
||||
** valid to do so, on the other hand, might cause SQLite to return incorrect
|
||||
** results.
|
||||
*/
|
||||
SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Identify and handle IN constraints in xBestIndex
|
||||
**
|
||||
** This interface may only be used from within an
|
||||
** [xBestIndex|xBestIndex() method] of a [virtual table] implementation.
|
||||
** The result of invoking this interface from any other context is
|
||||
** undefined and probably harmful.
|
||||
**
|
||||
** ^(A constraint on a virtual table of the form
|
||||
** "[IN operator|column IN (...)]" is
|
||||
** communicated to the xBestIndex method as a
|
||||
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
|
||||
** this constraint, it must set the corresponding
|
||||
** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
|
||||
** the usual mode of handling IN operators, SQLite generates [bytecode]
|
||||
** that invokes the [xFilter|xFilter() method] once for each value
|
||||
** on the right-hand side of the IN operator.)^ Thus the virtual table
|
||||
** only sees a single value from the right-hand side of the IN operator
|
||||
** at a time.
|
||||
**
|
||||
** In some cases, however, it would be advantageous for the virtual
|
||||
** table to see all values on the right-hand of the IN operator all at
|
||||
** once. The sqlite3_vtab_in() interfaces facilitates this in two ways:
|
||||
**
|
||||
** <ol>
|
||||
** <li><p>
|
||||
** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero)
|
||||
** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint
|
||||
** is an [IN operator] that can be processed all at once. ^In other words,
|
||||
** sqlite3_vtab_in() with -1 in the third argument is a mechanism
|
||||
** by which the virtual table can ask SQLite if all-at-once processing
|
||||
** of the IN operator is even possible.
|
||||
**
|
||||
** <li><p>
|
||||
** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates
|
||||
** to SQLite that the virtual table does or does not want to process
|
||||
** the IN operator all-at-once, respectively. ^Thus when the third
|
||||
** parameter (F) is non-negative, this interface is the mechanism by
|
||||
** which the virtual table tells SQLite how it wants to process the
|
||||
** IN operator.
|
||||
** </ol>
|
||||
**
|
||||
** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times
|
||||
** within the same xBestIndex method call. ^For any given P,N pair,
|
||||
** the return value from sqlite3_vtab_in(P,N,F) will always be the same
|
||||
** within the same xBestIndex call. ^If the interface returns true
|
||||
** (non-zero), that means that the constraint is an IN operator
|
||||
** that can be processed all-at-once. ^If the constraint is not an IN
|
||||
** operator or cannot be processed all-at-once, then the interface returns
|
||||
** false.
|
||||
**
|
||||
** ^(All-at-once processing of the IN operator is selected if both of the
|
||||
** following conditions are met:
|
||||
**
|
||||
** <ol>
|
||||
** <li><p> The P->aConstraintUsage[N].argvIndex value is set to a positive
|
||||
** integer. This is how the virtual table tells SQLite that it wants to
|
||||
** use the N-th constraint.
|
||||
**
|
||||
** <li><p> The last call to sqlite3_vtab_in(P,N,F) for which F was
|
||||
** non-negative had F>=1.
|
||||
** </ol>)^
|
||||
**
|
||||
** ^If either or both of the conditions above are false, then SQLite uses
|
||||
** the traditional one-at-a-time processing strategy for the IN constraint.
|
||||
** ^If both conditions are true, then the argvIndex-th parameter to the
|
||||
** xFilter method will be an [sqlite3_value] that appears to be NULL,
|
||||
** but which can be passed to [sqlite3_vtab_in_first()] and
|
||||
** [sqlite3_vtab_in_next()] to find all values on the right-hand side
|
||||
** of the IN constraint.
|
||||
*/
|
||||
SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Find all elements on the right-hand side of an IN constraint.
|
||||
**
|
||||
** These interfaces are only useful from within the
|
||||
** [xFilter|xFilter() method] of a [virtual table] implementation.
|
||||
** The result of invoking these interfaces from any other context
|
||||
** is undefined and probably harmful.
|
||||
**
|
||||
** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
|
||||
** sqlite3_vtab_in_next(X,P) must be one of the parameters to the
|
||||
** xFilter method which invokes these routines, and specifically
|
||||
** a parameter that was previously selected for all-at-once IN constraint
|
||||
** processing use the [sqlite3_vtab_in()] interface in the
|
||||
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
||||
** an xFilter argument that was selected for all-at-once IN constraint
|
||||
** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
|
||||
** exhibit some other undefined or harmful behavior.
|
||||
**
|
||||
** ^(Use these routines to access all values on the right-hand side
|
||||
** of the IN constraint using code like the following:
|
||||
**
|
||||
** <blockquote><pre>
|
||||
** for(rc=sqlite3_vtab_in_first(pList, &pVal);
|
||||
** rc==SQLITE_OK && pVal
|
||||
** rc=sqlite3_vtab_in_next(pList, &pVal)
|
||||
** ){
|
||||
** // do something with pVal
|
||||
** }
|
||||
** if( rc!=SQLITE_OK ){
|
||||
** // an error has occurred
|
||||
** }
|
||||
** </pre></blockquote>)^
|
||||
**
|
||||
** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P)
|
||||
** routines return SQLITE_OK and set *P to point to the first or next value
|
||||
** on the RHS of the IN constraint. ^If there are no more values on the
|
||||
** right hand side of the IN constraint, then *P is set to NULL and these
|
||||
** routines return [SQLITE_DONE]. ^The return value might be
|
||||
** some other value, such as SQLITE_NOMEM, in the event of a malfunction.
|
||||
**
|
||||
** The *ppOut values returned by these routines are only valid until the
|
||||
** next call to either of these routines or until the end of the xFilter
|
||||
** method from which these routines were called. If the virtual table
|
||||
** implementation needs to retain the *ppOut values for longer, it must make
|
||||
** copies. The *ppOut values are [protected sqlite3_value|protected].
|
||||
*/
|
||||
SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
|
||||
SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Constraint values in xBestIndex()
|
||||
** METHOD: sqlite3_index_info
|
||||
**
|
||||
** This API may only be used from within the [xBestIndex|xBestIndex method]
|
||||
** of a [virtual table] implementation. The result of calling this interface
|
||||
** from outside of an xBestIndex method are undefined and probably harmful.
|
||||
**
|
||||
** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
|
||||
** the [xBestIndex] method of a [virtual table] implementation, with P being
|
||||
** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and
|
||||
** J being a 0-based index into P->aConstraint[], then this routine
|
||||
** attempts to set *V to the value of the right-hand operand of
|
||||
** that constraint if the right-hand operand is known. ^If the
|
||||
** right-hand operand is not known, then *V is set to a NULL pointer.
|
||||
** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if
|
||||
** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
|
||||
** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
|
||||
** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
|
||||
** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
||||
** something goes wrong.
|
||||
**
|
||||
** The sqlite3_vtab_rhs_value() interface is usually only successful if
|
||||
** the right-hand operand of a constraint is a literal value in the original
|
||||
** SQL statement. If the right-hand operand is an expression or a reference
|
||||
** to some other column or a [host parameter], then sqlite3_vtab_rhs_value()
|
||||
** will probably return [SQLITE_NOTFOUND].
|
||||
**
|
||||
** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and
|
||||
** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such
|
||||
** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^
|
||||
**
|
||||
** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value
|
||||
** and remains valid for the duration of the xBestIndex method call.
|
||||
** ^When xBestIndex returns, the sqlite3_value object returned by
|
||||
** sqlite3_vtab_rhs_value() is automatically deallocated.
|
||||
**
|
||||
** The "_rhs_" in the name of this routine is an abbreviation for
|
||||
** "Right-Hand Side".
|
||||
*/
|
||||
SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Conflict resolution modes
|
||||
** KEYWORDS: {conflict resolution mode}
|
||||
|
14
src/libs/3rdparty/sqlite/sqlite3ext.h
vendored
14
src/libs/3rdparty/sqlite/sqlite3ext.h
vendored
@@ -344,6 +344,13 @@ struct sqlite3_api_routines {
|
||||
int (*autovacuum_pages)(sqlite3*,
|
||||
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
||||
void*, void(*)(void*));
|
||||
/* Version 3.38.0 and later */
|
||||
int (*error_offset)(sqlite3*);
|
||||
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
||||
int (*vtab_distinct)(sqlite3_index_info*);
|
||||
int (*vtab_in)(sqlite3_index_info*,int,int);
|
||||
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
||||
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -655,6 +662,13 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_total_changes64 sqlite3_api->total_changes64
|
||||
/* Version 3.37.0 and later */
|
||||
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
||||
/* Version 3.38.0 and later */
|
||||
#define sqlite3_error_offset sqlite3_api->error_offset
|
||||
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
||||
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
||||
#define sqlite3_vtab_in sqlite3_api->vtab_in
|
||||
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
||||
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
@@ -11,6 +11,7 @@ add_qtc_library(Sqlite
|
||||
PUBLIC_DEFINES
|
||||
SQLITE_CORE
|
||||
DEPENDS Qt5::Core Threads::Threads ${CMAKE_DL_LIBS}
|
||||
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.2.0
|
||||
PUBLIC_INCLUDES
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
../3rdparty/sqlite
|
||||
|
@@ -154,6 +154,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
BasicSmallString(const std::wstring &wstring)
|
||||
: BasicSmallString(BasicSmallString::fromQStringView(wstring))
|
||||
{}
|
||||
|
||||
template<typename BeginIterator,
|
||||
typename EndIterator,
|
||||
typename = std::enable_if_t<std::is_same<BeginIterator, EndIterator>::value>
|
||||
@@ -487,11 +491,31 @@ public:
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStringEncoder encoder{QStringEncoder::Utf8};
|
||||
|
||||
size_type oldSize = size();
|
||||
size_type newSize = oldSize + static_cast<size_type>(encoder.requiredSpace(string.size()));
|
||||
constexpr size_type temporaryArraySize = Size * 6;
|
||||
|
||||
reserve(optimalCapacity(newSize));
|
||||
auto newEnd = encoder.appendToBuffer(data() + size(), string);
|
||||
size_type oldSize = size();
|
||||
size_type maximumRequiredSize = static_cast<size_type>(encoder.requiredSpace(oldSize));
|
||||
char *newEnd = nullptr;
|
||||
|
||||
if (maximumRequiredSize > temporaryArraySize) {
|
||||
size_type newSize = oldSize + maximumRequiredSize;
|
||||
|
||||
reserve(optimalCapacity(newSize));
|
||||
newEnd = encoder.appendToBuffer(data() + oldSize, string);
|
||||
} else {
|
||||
char temporaryArray[temporaryArraySize];
|
||||
|
||||
auto newTemporaryArrayEnd = encoder.appendToBuffer(temporaryArray, string);
|
||||
|
||||
auto newAppendedStringSize = newTemporaryArrayEnd - temporaryArray;
|
||||
size_type newSize = oldSize + newAppendedStringSize;
|
||||
|
||||
reserve(optimalCapacity(newSize));
|
||||
|
||||
std::memcpy(data() + oldSize, temporaryArray, newAppendedStringSize);
|
||||
|
||||
newEnd = data() + newSize;
|
||||
}
|
||||
*newEnd = 0;
|
||||
setSize(newEnd - data());
|
||||
#else
|
||||
|
@@ -3,11 +3,28 @@ if (APPLE)
|
||||
set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/QmlDesigner")
|
||||
endif()
|
||||
|
||||
get_filename_component(
|
||||
QMLDOM_STANDALONE_CMAKELISTS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../qmldom_standalone/src/qmldom/standalone/"
|
||||
ABSOLUTE
|
||||
)
|
||||
|
||||
if(EXISTS ${QMLDOM_STANDALONE_CMAKELISTS} AND Qt6_FOUND AND NOT TARGET qmldomlib)
|
||||
add_subdirectory(
|
||||
../../../../qmldom_standalone/src/qmldom/standalone
|
||||
${CMAKE_BINARY_DIR}/qmldom_standalone)
|
||||
|
||||
set_target_properties(qmldomlib PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,RUNTIME_OUTPUT_DIRECTORY>"
|
||||
LIBRARY_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,LIBRARY_OUTPUT_DIRECTORY>")
|
||||
endif()
|
||||
|
||||
add_qtc_plugin(QmlDesigner
|
||||
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.2.0 AND TARGET Qt5::QuickWidgets AND TARGET Qt5::Svg
|
||||
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.2.0 AND TARGET Qt5::QuickWidgets AND TARGET Qt5::Svg AND TARGET qmldomlib
|
||||
DEPENDS
|
||||
QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
|
||||
Qt5::QuickWidgets Qt5::CorePrivate Sqlite Qt5::Xml Qt5::Svg
|
||||
qmldomlib
|
||||
DEFINES
|
||||
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
|
||||
SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner"
|
||||
@@ -402,6 +419,39 @@ extend_qtc_plugin(QmlDesigner
|
||||
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX designercore/projectstorage
|
||||
SOURCES
|
||||
directorypathcompressor.h
|
||||
filesysteminterface.h
|
||||
filesystem.cpp filesystem.h
|
||||
filestatus.h
|
||||
filestatuscache.cpp filestatuscache.h
|
||||
nonlockingmutex.h
|
||||
projectstorageinterface.h
|
||||
projectstorage.h
|
||||
projectstoragepathwatcher.h
|
||||
projectstoragepathwatcherinterface.h
|
||||
projectstoragepathwatchernotifierinterface.h
|
||||
projectstoragepathwatcher.h
|
||||
projectstoragepathwatchertypes.h
|
||||
projectstorageprinting.h
|
||||
projectstoragetypes.h
|
||||
projectstorageupdater.cpp projectstorageupdater.h
|
||||
sourcepath.h
|
||||
sourcepathcache.h
|
||||
sourcepathcache.h
|
||||
sourcepathcachetypes.h
|
||||
sourcepathview.h
|
||||
storagecache.h
|
||||
storagecacheentry.h
|
||||
storagecachefwd.h
|
||||
qmldocumentparserinterface.h
|
||||
qmltypesparserinterface.h
|
||||
qmltypesparser.cpp qmltypesparser.h
|
||||
qmldocumentparser.cpp qmldocumentparser.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX designercore/instances
|
||||
SOURCES
|
||||
|
@@ -98,7 +98,8 @@ enum class BasicIdType {
|
||||
ProjectPartId,
|
||||
Import,
|
||||
ImportedTypeName,
|
||||
ExportedTypeName
|
||||
ExportedTypeName,
|
||||
ModuleExportedImport
|
||||
};
|
||||
|
||||
using TypeId = BasicId<BasicIdType::Type>;
|
||||
@@ -137,4 +138,7 @@ using ImportedTypeNameIds = std::vector<ImportedTypeNameId>;
|
||||
using ExportedTypeNameId = BasicId<BasicIdType::ExportedTypeName>;
|
||||
using ExportedTypeNameIds = std::vector<ExportedTypeNameId>;
|
||||
|
||||
using ModuleExportedImportId = BasicId<BasicIdType::ModuleExportedImport>;
|
||||
using ModuleExportedImportIds = std::vector<ModuleExportedImportId>;
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -77,6 +77,15 @@ FileStatus FileSystem::fileStatus(SourceId sourceId) const
|
||||
return FileStatus{sourceId, -1, -1};
|
||||
}
|
||||
|
||||
QString FileSystem::contentAsQString(const QString &filePath) const
|
||||
{
|
||||
QFile file{filePath};
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
return QString::fromUtf8(file.readAll());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void FileSystem::remove(const SourceIds &sourceIds)
|
||||
{
|
||||
for (SourceId sourceId : sourceIds)
|
||||
|
@@ -53,6 +53,7 @@ public:
|
||||
SourceIds directoryEntries(const QString &directoryPath) const override;
|
||||
long long lastModified(SourceId sourceId) const override;
|
||||
FileStatus fileStatus(SourceId sourceId) const override;
|
||||
QString contentAsQString(const QString &filePath) const override;
|
||||
|
||||
void remove(const SourceIds &sourceIds) override;
|
||||
|
||||
|
@@ -1,39 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ProjectManagerInterface
|
||||
{
|
||||
public:
|
||||
virtual QStringList qtQmlDirs() const = 0;
|
||||
|
||||
protected:
|
||||
~ProjectManagerInterface() = default;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -40,6 +40,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
@@ -81,7 +83,12 @@ public:
|
||||
std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end());
|
||||
|
||||
synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds);
|
||||
synchronizeImports(package.imports, package.updatedSourceIds);
|
||||
synchronizeImports(package.imports,
|
||||
package.updatedSourceIds,
|
||||
package.moduleDependencies,
|
||||
package.updatedModuleDependencySourceIds,
|
||||
package.moduleExportedImports,
|
||||
package.updatedModuleIds);
|
||||
synchronizeTypes(package.types,
|
||||
updatedTypeIds,
|
||||
insertedAliasPropertyDeclarations,
|
||||
@@ -392,11 +399,13 @@ private:
|
||||
PropertyDeclarationId propertyDeclarationId,
|
||||
ImportedTypeNameId aliasImportedTypeNameId,
|
||||
Utils::SmallString aliasPropertyName,
|
||||
Utils::SmallString aliasPropertyNameTail,
|
||||
PropertyDeclarationId aliasPropertyDeclarationId = PropertyDeclarationId{})
|
||||
: typeId{typeId}
|
||||
, propertyDeclarationId{propertyDeclarationId}
|
||||
, aliasImportedTypeNameId{aliasImportedTypeNameId}
|
||||
, aliasPropertyName{std::move(aliasPropertyName)}
|
||||
, aliasPropertyNameTail{std::move(aliasPropertyNameTail)}
|
||||
, aliasPropertyDeclarationId{aliasPropertyDeclarationId}
|
||||
{}
|
||||
|
||||
@@ -412,6 +421,7 @@ private:
|
||||
PropertyDeclarationId propertyDeclarationId;
|
||||
ImportedTypeNameId aliasImportedTypeNameId;
|
||||
Utils::SmallString aliasPropertyName;
|
||||
Utils::SmallString aliasPropertyNameTail;
|
||||
PropertyDeclarationId aliasPropertyDeclarationId;
|
||||
};
|
||||
|
||||
@@ -682,32 +692,72 @@ private:
|
||||
Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove);
|
||||
}
|
||||
|
||||
void synchronizeImports(Storage::Imports &imports, const SourceIds &updatedSourceIds)
|
||||
void synchronizeImports(Storage::Imports &imports,
|
||||
const SourceIds &updatedSourceIds,
|
||||
Storage::Imports &moduleDependencies,
|
||||
const SourceIds &updatedModuleDependencySourceIds,
|
||||
Storage::ModuleExportedImports &moduleExportedImports,
|
||||
const ModuleIds &updatedModuleIds)
|
||||
{
|
||||
deleteDocumentImportsForDeletedDocuments(imports, updatedSourceIds);
|
||||
|
||||
synchronizeDocumentImports(imports, updatedSourceIds);
|
||||
synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds);
|
||||
synchronizeDocumentImports(imports, updatedSourceIds, Storage::ImportKind::Import);
|
||||
synchronizeDocumentImports(moduleDependencies,
|
||||
updatedModuleDependencySourceIds,
|
||||
Storage::ImportKind::ModuleDependency);
|
||||
}
|
||||
|
||||
void deleteDocumentImportsForDeletedDocuments(Storage::Imports &imports,
|
||||
const SourceIds &updatedSourceIds)
|
||||
void synchromizeModuleExportedImports(Storage::ModuleExportedImports &moduleExportedImports,
|
||||
const ModuleIds &updatedModuleIds)
|
||||
{
|
||||
SourceIds importSourceIds = Utils::transform<SourceIds>(imports,
|
||||
[](const Storage::Import &import) {
|
||||
return import.sourceId;
|
||||
});
|
||||
std::sort(moduleExportedImports.begin(),
|
||||
moduleExportedImports.end(),
|
||||
[](auto &&first, auto &&second) {
|
||||
return std::tie(first.moduleId, first.exportedModuleId)
|
||||
< std::tie(second.moduleId, second.exportedModuleId);
|
||||
});
|
||||
|
||||
std::sort(importSourceIds.begin(), importSourceIds.end());
|
||||
auto range = selectModuleExportedImportsForSourceIdStatement
|
||||
.template range<Storage::ModuleExportedImportView>(
|
||||
toIntegers(updatedModuleIds));
|
||||
|
||||
SourceIds documentSourceIdsToBeDeleted;
|
||||
auto compareKey = [](const Storage::ModuleExportedImportView &view,
|
||||
const Storage::ModuleExportedImport &import) -> long long {
|
||||
auto moduleIdDifference = &view.moduleId - &import.moduleId;
|
||||
if (moduleIdDifference != 0)
|
||||
return moduleIdDifference;
|
||||
|
||||
std::set_difference(updatedSourceIds.begin(),
|
||||
updatedSourceIds.end(),
|
||||
importSourceIds.begin(),
|
||||
importSourceIds.end(),
|
||||
std::back_inserter(documentSourceIdsToBeDeleted));
|
||||
return &view.exportedModuleId - &import.exportedModuleId;
|
||||
};
|
||||
|
||||
deleteDocumentImportsWithSourceIdsStatement.write(toIntegers(documentSourceIdsToBeDeleted));
|
||||
auto insert = [&](const Storage::ModuleExportedImport &import) {
|
||||
if (import.version.minor) {
|
||||
insertModuleExportedImportWithVersionStatement.write(&import.moduleId,
|
||||
&import.exportedModuleId,
|
||||
to_underlying(import.isAutoVersion),
|
||||
import.version.major.value,
|
||||
import.version.minor.value);
|
||||
} else if (import.version.major) {
|
||||
insertModuleExportedImportWithMajorVersionStatement.write(&import.moduleId,
|
||||
&import.exportedModuleId,
|
||||
to_underlying(
|
||||
import.isAutoVersion),
|
||||
import.version.major.value);
|
||||
} else {
|
||||
insertModuleExportedImportWithoutVersionStatement.write(&import.moduleId,
|
||||
&import.exportedModuleId,
|
||||
to_underlying(
|
||||
import.isAutoVersion));
|
||||
}
|
||||
};
|
||||
|
||||
auto update = [](const Storage::ModuleExportedImportView &,
|
||||
const Storage::ModuleExportedImport &) { return Sqlite::UpdateChange::No; };
|
||||
|
||||
auto remove = [&](const Storage::ModuleExportedImportView &view) {
|
||||
deleteModuleExportedImportStatement.write(&view.moduleExportedImportId);
|
||||
};
|
||||
|
||||
Sqlite::insertUpdateDelete(range, moduleExportedImports, compareKey, insert, update, remove);
|
||||
}
|
||||
|
||||
ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const
|
||||
@@ -736,15 +786,21 @@ private:
|
||||
auto callback = [&](long long typeId,
|
||||
long long propertyDeclarationId,
|
||||
long long propertyImportedTypeNameId,
|
||||
long long aliasPropertyDeclarationId) {
|
||||
long long aliasPropertyDeclarationId,
|
||||
long long aliasPropertyDeclarationTailId) {
|
||||
auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>(
|
||||
aliasPropertyDeclarationId);
|
||||
Utils::SmallString aliasPropertyNameTail;
|
||||
if (aliasPropertyDeclarationTailId != -1)
|
||||
aliasPropertyNameTail = selectPropertyNameStatement.template value<Utils::SmallString>(
|
||||
aliasPropertyDeclarationTailId);
|
||||
|
||||
relinkableAliasPropertyDeclarations
|
||||
.emplace_back(TypeId{typeId},
|
||||
PropertyDeclarationId{propertyDeclarationId},
|
||||
ImportedTypeNameId{propertyImportedTypeNameId},
|
||||
std::move(aliasPropertyName));
|
||||
std::move(aliasPropertyName),
|
||||
std::move(aliasPropertyNameTail));
|
||||
|
||||
updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId);
|
||||
|
||||
@@ -919,6 +975,20 @@ private:
|
||||
relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds);
|
||||
}
|
||||
|
||||
PropertyDeclarationId fetchAliasId(TypeId aliasTypeId,
|
||||
Utils::SmallStringView aliasPropertyName,
|
||||
Utils::SmallStringView aliasPropertyNameTail)
|
||||
{
|
||||
if (aliasPropertyNameTail.empty())
|
||||
return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName);
|
||||
|
||||
auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId,
|
||||
aliasPropertyName);
|
||||
|
||||
return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId,
|
||||
aliasPropertyNameTail);
|
||||
}
|
||||
|
||||
void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations)
|
||||
{
|
||||
for (const auto &aliasDeclaration : aliasDeclarations) {
|
||||
@@ -927,8 +997,9 @@ private:
|
||||
if (!aliasTypeId)
|
||||
throw TypeNameDoesNotExists{};
|
||||
|
||||
auto aliasId = fetchPropertyDeclarationIdByTypeIdAndNameUngarded(
|
||||
aliasTypeId, aliasDeclaration.aliasPropertyName);
|
||||
auto aliasId = fetchAliasId(aliasTypeId,
|
||||
aliasDeclaration.aliasPropertyName,
|
||||
aliasDeclaration.aliasPropertyNameTail);
|
||||
|
||||
updatePropertyDeclarationAliasIdAndTypeNameIdStatement
|
||||
.write(&aliasDeclaration.propertyDeclarationId,
|
||||
@@ -973,8 +1044,19 @@ private:
|
||||
Prototypes &relinkablePrototypes)
|
||||
{
|
||||
std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) {
|
||||
return std::tie(first.moduleId, first.name, first.version)
|
||||
< std::tie(second.moduleId, second.name, second.version);
|
||||
if (first.moduleId < second.moduleId)
|
||||
return true;
|
||||
else if (first.moduleId > second.moduleId)
|
||||
return false;
|
||||
|
||||
auto nameCompare = Sqlite::compare(first.name, second.name);
|
||||
|
||||
if (nameCompare < 0)
|
||||
return true;
|
||||
else if (nameCompare > 0)
|
||||
return false;
|
||||
|
||||
return first.version < second.version;
|
||||
});
|
||||
|
||||
auto range = selectExportedTypesForSourceIdsStatement.template range<Storage::ExportedTypeView>(
|
||||
@@ -1020,7 +1102,7 @@ private:
|
||||
&type.typeId);
|
||||
}
|
||||
} catch (const Sqlite::ConstraintPreventsModification &) {
|
||||
throw QmlDesigner::ModuleDoesNotExists{};
|
||||
throw QmlDesigner::ExportedTypeCannotBeInserted{};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1058,7 +1140,8 @@ private:
|
||||
PropertyDeclarationId{propertyDeclarationId},
|
||||
fetchImportedTypeNameId(value.typeName,
|
||||
sourceId),
|
||||
std::move(value.aliasPropertyName));
|
||||
value.aliasPropertyName,
|
||||
value.aliasPropertyNameTail);
|
||||
return Sqlite::CallbackControl::Abort;
|
||||
};
|
||||
|
||||
@@ -1075,12 +1158,8 @@ private:
|
||||
if (!propertyTypeId)
|
||||
throw TypeNameDoesNotExists{};
|
||||
|
||||
auto propertyDeclarationId = insertPropertyDeclarationStatement.template value<
|
||||
PropertyDeclarationId>(&typeId,
|
||||
value.name,
|
||||
&propertyTypeId,
|
||||
static_cast<int>(value.traits),
|
||||
&propertyImportedTypeNameId);
|
||||
auto propertyDeclarationId = insertPropertyDeclarationStatement.template value<PropertyDeclarationId>(
|
||||
&typeId, value.name, &propertyTypeId, to_underlying(value.traits), &propertyImportedTypeNameId);
|
||||
|
||||
auto nextPropertyDeclarationId = selectPropertyDeclarationIdPrototypeChainDownStatement
|
||||
.template value<PropertyDeclarationId>(&typeId,
|
||||
@@ -1089,7 +1168,7 @@ private:
|
||||
updateAliasIdPropertyDeclarationStatement.write(&nextPropertyDeclarationId,
|
||||
&propertyDeclarationId);
|
||||
updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement
|
||||
.write(&propertyDeclarationId, &propertyTypeId, static_cast<int>(value.traits));
|
||||
.write(&propertyDeclarationId, &propertyTypeId, to_underlying(value.traits));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1104,6 +1183,7 @@ private:
|
||||
fetchImportedTypeNameId(value.typeName,
|
||||
sourceId),
|
||||
value.aliasPropertyName,
|
||||
value.aliasPropertyNameTail,
|
||||
view.aliasId);
|
||||
}
|
||||
|
||||
@@ -1125,10 +1205,10 @@ private:
|
||||
|
||||
updatePropertyDeclarationStatement.write(&view.id,
|
||||
&propertyTypeId,
|
||||
static_cast<int>(value.traits),
|
||||
to_underlying(value.traits),
|
||||
&propertyImportedTypeNameId);
|
||||
updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement
|
||||
.write(&view.id, &propertyTypeId, static_cast<int>(value.traits));
|
||||
.write(&view.id, &propertyTypeId, to_underlying(value.traits));
|
||||
propertyDeclarationIds.push_back(view.id);
|
||||
return Sqlite::UpdateChange::Update;
|
||||
}
|
||||
@@ -1263,7 +1343,38 @@ private:
|
||||
PropertyCompare<AliasPropertyDeclaration>{});
|
||||
}
|
||||
|
||||
void synchronizeDocumentImports(Storage::Imports &imports, const SourceIds &updatedSourceIds)
|
||||
void insertDocumentImport(const Storage::Import &import,
|
||||
Storage::ImportKind importKind,
|
||||
ModuleId sourceModuleId,
|
||||
ModuleExportedImportId moduleExportedImportId)
|
||||
{
|
||||
if (import.version.minor) {
|
||||
insertDocumentImportWithVersionStatement.write(&import.sourceId,
|
||||
&import.moduleId,
|
||||
&sourceModuleId,
|
||||
to_underlying(importKind),
|
||||
import.version.major.value,
|
||||
import.version.minor.value,
|
||||
&moduleExportedImportId);
|
||||
} else if (import.version.major) {
|
||||
insertDocumentImportWithMajorVersionStatement.write(&import.sourceId,
|
||||
&import.moduleId,
|
||||
&sourceModuleId,
|
||||
to_underlying(importKind),
|
||||
import.version.major.value,
|
||||
&moduleExportedImportId);
|
||||
} else {
|
||||
insertDocumentImportWithoutVersionStatement.write(&import.sourceId,
|
||||
&import.moduleId,
|
||||
&sourceModuleId,
|
||||
to_underlying(importKind),
|
||||
&moduleExportedImportId);
|
||||
}
|
||||
}
|
||||
|
||||
void synchronizeDocumentImports(Storage::Imports &imports,
|
||||
const SourceIds &updatedSourceIds,
|
||||
Storage::ImportKind importKind)
|
||||
{
|
||||
std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
|
||||
return std::tie(first.sourceId, first.moduleId, first.version)
|
||||
@@ -1271,7 +1382,7 @@ private:
|
||||
});
|
||||
|
||||
auto range = selectDocumentImportForSourceIdStatement.template range<Storage::ImportView>(
|
||||
toIntegers(updatedSourceIds));
|
||||
toIntegers(updatedSourceIds), to_underlying(importKind));
|
||||
|
||||
auto compareKey = [](const Storage::ImportView &view,
|
||||
const Storage::Import &import) -> long long {
|
||||
@@ -1291,18 +1402,31 @@ private:
|
||||
};
|
||||
|
||||
auto insert = [&](const Storage::Import &import) {
|
||||
if (import.version.minor) {
|
||||
insertDocumentImportWithVersionStatement.write(&import.sourceId,
|
||||
&import.moduleId,
|
||||
import.version.major.value,
|
||||
import.version.minor.value);
|
||||
} else if (import.version.major) {
|
||||
insertDocumentImportWithMajorVersionStatement.write(&import.sourceId,
|
||||
&import.moduleId,
|
||||
import.version.major.value);
|
||||
} else {
|
||||
insertDocumentImportWithoutVersionStatement.write(&import.sourceId, &import.moduleId);
|
||||
}
|
||||
insertDocumentImport(import, importKind, import.moduleId, ModuleExportedImportId{});
|
||||
auto callback = [&](int exportedModuleId,
|
||||
int majorVersion,
|
||||
int minorVersion,
|
||||
long long moduleExportedImportId) {
|
||||
Storage::Import additionImport{ModuleId{exportedModuleId},
|
||||
Storage::Version{majorVersion, minorVersion},
|
||||
import.sourceId};
|
||||
|
||||
auto exportedImportKind = importKind == Storage::ImportKind::Import
|
||||
? Storage::ImportKind::ModuleExportedImport
|
||||
: Storage::ImportKind::ModuleExportedModuleDependency;
|
||||
|
||||
insertDocumentImport(additionImport,
|
||||
exportedImportKind,
|
||||
import.moduleId,
|
||||
ModuleExportedImportId{moduleExportedImportId});
|
||||
|
||||
return Sqlite::CallbackControl::Continue;
|
||||
};
|
||||
|
||||
selectModuleExportedImportsForModuleIdStatement.readCallback(callback,
|
||||
&import.moduleId,
|
||||
import.version.major.value,
|
||||
import.version.minor.value);
|
||||
};
|
||||
|
||||
auto update = [](const Storage::ImportView &, const Storage::Import &) {
|
||||
@@ -1316,7 +1440,7 @@ private:
|
||||
Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove);
|
||||
}
|
||||
|
||||
Utils::PathString createJson(const Storage::ParameterDeclarations ¶meters)
|
||||
static Utils::PathString createJson(const Storage::ParameterDeclarations ¶meters)
|
||||
{
|
||||
Utils::PathString json;
|
||||
json.append("[");
|
||||
@@ -1334,7 +1458,7 @@ private:
|
||||
json.append("\"}");
|
||||
} else {
|
||||
json.append("\",\"tr\":");
|
||||
json.append(Utils::SmallString::number(static_cast<int>(parameter.traits)));
|
||||
json.append(Utils::SmallString::number(to_underlying(parameter.traits)));
|
||||
json.append("}");
|
||||
}
|
||||
}
|
||||
@@ -1350,7 +1474,16 @@ private:
|
||||
std::sort(functionsDeclarations.begin(),
|
||||
functionsDeclarations.end(),
|
||||
[](auto &&first, auto &&second) {
|
||||
return Sqlite::compare(first.name, second.name) < 0;
|
||||
auto compare = Sqlite::compare(first.name, second.name);
|
||||
|
||||
if (compare == 0) {
|
||||
Utils::PathString firstSignature{createJson(first.parameters)};
|
||||
Utils::PathString secondSignature{createJson(second.parameters)};
|
||||
|
||||
return Sqlite::compare(firstSignature, secondSignature) < 0;
|
||||
}
|
||||
|
||||
return compare < 0;
|
||||
});
|
||||
|
||||
auto range = selectFunctionDeclarationsForTypeIdStatement
|
||||
@@ -1358,7 +1491,13 @@ private:
|
||||
|
||||
auto compareKey = [](const Storage::FunctionDeclarationView &view,
|
||||
const Storage::FunctionDeclaration &value) {
|
||||
return Sqlite::compare(view.name, value.name);
|
||||
auto nameKey = Sqlite::compare(view.name, value.name);
|
||||
if (nameKey != 0)
|
||||
return nameKey;
|
||||
|
||||
Utils::PathString valueSignature{createJson(value.parameters)};
|
||||
|
||||
return Sqlite::compare(view.signature, valueSignature);
|
||||
};
|
||||
|
||||
auto insert = [&](const Storage::FunctionDeclaration &value) {
|
||||
@@ -1371,10 +1510,10 @@ private:
|
||||
const Storage::FunctionDeclaration &value) {
|
||||
Utils::PathString signature{createJson(value.parameters)};
|
||||
|
||||
if (value.returnTypeName == view.returnTypeName && signature == view.signature)
|
||||
if (value.returnTypeName == view.returnTypeName)
|
||||
return Sqlite::UpdateChange::No;
|
||||
|
||||
updateFunctionDeclarationStatement.write(&view.id, value.returnTypeName, signature);
|
||||
updateFunctionDeclarationStatement.write(&view.id, value.returnTypeName);
|
||||
|
||||
return Sqlite::UpdateChange::Update;
|
||||
};
|
||||
@@ -1389,7 +1528,16 @@ private:
|
||||
void synchronizeSignalDeclarations(TypeId typeId, Storage::SignalDeclarations &signalDeclarations)
|
||||
{
|
||||
std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) {
|
||||
return Sqlite::compare(first.name, second.name) < 0;
|
||||
auto compare = Sqlite::compare(first.name, second.name);
|
||||
|
||||
if (compare == 0) {
|
||||
Utils::PathString firstSignature{createJson(first.parameters)};
|
||||
Utils::PathString secondSignature{createJson(second.parameters)};
|
||||
|
||||
return Sqlite::compare(firstSignature, secondSignature) < 0;
|
||||
}
|
||||
|
||||
return compare < 0;
|
||||
});
|
||||
|
||||
auto range = selectSignalDeclarationsForTypeIdStatement
|
||||
@@ -1397,7 +1545,13 @@ private:
|
||||
|
||||
auto compareKey = [](const Storage::SignalDeclarationView &view,
|
||||
const Storage::SignalDeclaration &value) {
|
||||
return Sqlite::compare(view.name, value.name);
|
||||
auto nameKey = Sqlite::compare(view.name, value.name);
|
||||
if (nameKey != 0)
|
||||
return nameKey;
|
||||
|
||||
Utils::PathString valueSignature{createJson(value.parameters)};
|
||||
|
||||
return Sqlite::compare(view.signature, valueSignature);
|
||||
};
|
||||
|
||||
auto insert = [&](const Storage::SignalDeclaration &value) {
|
||||
@@ -1408,14 +1562,7 @@ private:
|
||||
|
||||
auto update = [&](const Storage::SignalDeclarationView &view,
|
||||
const Storage::SignalDeclaration &value) {
|
||||
Utils::PathString signature{createJson(value.parameters)};
|
||||
|
||||
if (signature == view.signature)
|
||||
return Sqlite::UpdateChange::No;
|
||||
|
||||
updateSignalDeclarationStatement.write(&view.id, signature);
|
||||
|
||||
return Sqlite::UpdateChange::Update;
|
||||
return Sqlite::UpdateChange::No;
|
||||
};
|
||||
|
||||
auto remove = [&](const Storage::SignalDeclarationView &view) {
|
||||
@@ -1425,7 +1572,7 @@ private:
|
||||
Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove);
|
||||
}
|
||||
|
||||
Utils::PathString createJson(const Storage::EnumeratorDeclarations &enumeratorDeclarations)
|
||||
static Utils::PathString createJson(const Storage::EnumeratorDeclarations &enumeratorDeclarations)
|
||||
{
|
||||
Utils::PathString json;
|
||||
json.append("{");
|
||||
@@ -1513,8 +1660,7 @@ private:
|
||||
|
||||
type.typeId = upsertTypeStatement.template value<TypeId>(&type.sourceId,
|
||||
type.typeName,
|
||||
static_cast<int>(
|
||||
type.accessSemantics));
|
||||
to_underlying(type.accessSemantics));
|
||||
|
||||
if (!type.typeId)
|
||||
type.typeId = selectTypeIdBySourceIdAndNameStatement.template value<TypeId>(&type.sourceId,
|
||||
@@ -1661,13 +1807,6 @@ private:
|
||||
{
|
||||
struct Inspect
|
||||
{
|
||||
auto operator()(const Storage::NativeType &nativeType)
|
||||
{
|
||||
return storage.fetchImportedTypeNameId(Storage::TypeNameKind::Native,
|
||||
&sourceId,
|
||||
nativeType.name);
|
||||
}
|
||||
|
||||
auto operator()(const Storage::ImportedType &importedType)
|
||||
{
|
||||
return storage.fetchImportedTypeNameId(Storage::TypeNameKind::Exported,
|
||||
@@ -1696,13 +1835,14 @@ private:
|
||||
Utils::SmallStringView typeName)
|
||||
{
|
||||
auto importedTypeNameId = selectImportedTypeNameIdStatement.template value<ImportedTypeNameId>(
|
||||
static_cast<int>(kind), id, typeName);
|
||||
to_underlying(kind), id, typeName);
|
||||
|
||||
if (importedTypeNameId)
|
||||
return importedTypeNameId;
|
||||
|
||||
return insertImportedTypeNameIdStatement
|
||||
.template value<ImportedTypeNameId>(static_cast<int>(kind), id, typeName);
|
||||
return insertImportedTypeNameIdStatement.template value<ImportedTypeNameId>(to_underlying(kind),
|
||||
id,
|
||||
typeName);
|
||||
}
|
||||
|
||||
TypeId fetchTypeId(ImportedTypeNameId typeNameId) const
|
||||
@@ -1878,6 +2018,7 @@ private:
|
||||
createEnumerationsTable(database);
|
||||
createFunctionsTable(database);
|
||||
createSignalsTable(database);
|
||||
createModuleExportedImportsTable(database, moduleIdColumn);
|
||||
createDocumentImportsTable(database, moduleIdColumn);
|
||||
createFileStatusesTable(database);
|
||||
createProjectDatasTable(database);
|
||||
@@ -1963,10 +2104,17 @@ private:
|
||||
propertyDeclarationTable,
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Restrict);
|
||||
auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn(
|
||||
"aliasPropertyDeclarationTailId",
|
||||
propertyDeclarationTable,
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Restrict);
|
||||
|
||||
propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
|
||||
propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
|
||||
"aliasPropertyDeclarationId IS NOT NULL");
|
||||
propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn},
|
||||
"aliasPropertyDeclarationTailId IS NOT NULL");
|
||||
|
||||
propertyDeclarationTable.initialize(database);
|
||||
}
|
||||
@@ -2042,10 +2190,10 @@ private:
|
||||
{Sqlite::PrimaryKey{}});
|
||||
auto &typeIdColumn = table.addColumn("typeId");
|
||||
auto &nameColumn = table.addColumn("name");
|
||||
table.addColumn("signature");
|
||||
auto &signatureColumn = table.addColumn("signature");
|
||||
table.addColumn("returnTypeName");
|
||||
|
||||
table.addUniqueIndex({typeIdColumn, nameColumn});
|
||||
table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
@@ -2058,9 +2206,9 @@ private:
|
||||
table.addColumn("signalDeclarationId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
auto &typeIdColumn = table.addColumn("typeId");
|
||||
auto &nameColumn = table.addColumn("name");
|
||||
table.addColumn("signature");
|
||||
auto &signatureColumn = table.addColumn("signature");
|
||||
|
||||
table.addUniqueIndex({typeIdColumn, nameColumn});
|
||||
table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
@@ -2082,6 +2230,30 @@ private:
|
||||
return std::move(modelIdColumn);
|
||||
}
|
||||
|
||||
void createModuleExportedImportsTable(Database &database,
|
||||
const Sqlite::Column &foreignModuleIdColumn)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("moduleExportedImports");
|
||||
table.addColumn("moduleExportedImportId",
|
||||
Sqlite::ColumnType::Integer,
|
||||
{Sqlite::PrimaryKey{}});
|
||||
auto &moduleIdColumn = table.addForeignKeyColumn("moduleId",
|
||||
foreignModuleIdColumn,
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Cascade,
|
||||
Sqlite::Enforment::Immediate);
|
||||
auto &sourceIdColumn = table.addColumn("exportedModuleId");
|
||||
table.addColumn("isAutoVersion");
|
||||
table.addColumn("majorVersion");
|
||||
table.addColumn("minorVersion");
|
||||
|
||||
table.addUniqueIndex({sourceIdColumn, moduleIdColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createDocumentImportsTable(Database &database, const Sqlite::Column &foreignModuleIdColumn)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
@@ -2093,16 +2265,37 @@ private:
|
||||
foreignModuleIdColumn,
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Cascade,
|
||||
Sqlite::Enforment::Deferred);
|
||||
Sqlite::Enforment::Immediate);
|
||||
auto &sourceModuleIdColumn = table.addForeignKeyColumn("sourceModuleId",
|
||||
foreignModuleIdColumn,
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Cascade,
|
||||
Sqlite::Enforment::Immediate);
|
||||
auto &kindColumn = table.addColumn("kind");
|
||||
auto &majorVersionColumn = table.addColumn("majorVersion");
|
||||
auto &minorVersionColumn = table.addColumn("minorVersion");
|
||||
table.addColumn("kind");
|
||||
auto &moduleExportedModuleIdColumn = table.addColumn("moduleExportedModuleId");
|
||||
|
||||
table.addUniqueIndex({sourceIdColumn, moduleIdColumn},
|
||||
table.addUniqueIndex({sourceIdColumn,
|
||||
moduleIdColumn,
|
||||
kindColumn,
|
||||
sourceModuleIdColumn,
|
||||
moduleExportedModuleIdColumn},
|
||||
"majorVersion IS NULL AND minorVersion IS NULL");
|
||||
table.addUniqueIndex({sourceIdColumn, moduleIdColumn, majorVersionColumn},
|
||||
table.addUniqueIndex({sourceIdColumn,
|
||||
moduleIdColumn,
|
||||
kindColumn,
|
||||
sourceModuleIdColumn,
|
||||
majorVersionColumn,
|
||||
moduleExportedModuleIdColumn},
|
||||
"majorVersion IS NOT NULL AND minorVersion IS NULL");
|
||||
table.addUniqueIndex({sourceIdColumn, moduleIdColumn, majorVersionColumn, minorVersionColumn},
|
||||
table.addUniqueIndex({sourceIdColumn,
|
||||
moduleIdColumn,
|
||||
kindColumn,
|
||||
sourceModuleIdColumn,
|
||||
majorVersionColumn,
|
||||
minorVersionColumn,
|
||||
moduleExportedModuleIdColumn},
|
||||
"majorVersion IS NOT NULL AND minorVersion IS NOT NULL");
|
||||
|
||||
table.initialize(database);
|
||||
@@ -2305,7 +2498,7 @@ public:
|
||||
database};
|
||||
mutable ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{
|
||||
"SELECT name, returnTypeName, signature, functionDeclarationId FROM "
|
||||
"functionDeclarations WHERE typeId=? ORDER BY name",
|
||||
"functionDeclarations WHERE typeId=? ORDER BY name, signature",
|
||||
database};
|
||||
mutable ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{
|
||||
"SELECT name, returnTypeName, functionDeclarationId FROM "
|
||||
@@ -2320,15 +2513,13 @@ public:
|
||||
"INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, "
|
||||
"?3, ?4)",
|
||||
database};
|
||||
WriteStatement<3> updateFunctionDeclarationStatement{
|
||||
"UPDATE functionDeclarations SET returnTypeName=?2, signature=?3 WHERE "
|
||||
"functionDeclarationId=?1",
|
||||
database};
|
||||
WriteStatement<2> updateFunctionDeclarationStatement{
|
||||
"UPDATE functionDeclarations SET returnTypeName=?2 WHERE functionDeclarationId=?1", database};
|
||||
WriteStatement<1> deleteFunctionDeclarationStatement{
|
||||
"DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database};
|
||||
mutable ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{
|
||||
"SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER "
|
||||
"BY name",
|
||||
"BY name, signature",
|
||||
database};
|
||||
mutable ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{
|
||||
"SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name",
|
||||
@@ -2380,22 +2571,22 @@ public:
|
||||
"SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND "
|
||||
"name=?3",
|
||||
database};
|
||||
mutable ReadStatement<5, 1> selectDocumentImportForSourceIdStatement{
|
||||
mutable ReadStatement<5, 2> selectDocumentImportForSourceIdStatement{
|
||||
"SELECT importId, sourceId, moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) "
|
||||
"FROM documentImports WHERE sourceId IN carray(?1) ORDER BY sourceId, moduleId, "
|
||||
"majorVersion, minorVersion",
|
||||
"FROM documentImports WHERE sourceId IN carray(?1) AND kind=?2 ORDER BY sourceId, "
|
||||
"moduleId, majorVersion, minorVersion",
|
||||
database};
|
||||
WriteStatement<2> insertDocumentImportWithoutVersionStatement{
|
||||
"INSERT INTO documentImports(sourceId, moduleId) "
|
||||
"VALUES (?1, ?2)",
|
||||
WriteStatement<5> insertDocumentImportWithoutVersionStatement{
|
||||
"INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, "
|
||||
"moduleExportedModuleId) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
database};
|
||||
WriteStatement<3> insertDocumentImportWithMajorVersionStatement{
|
||||
"INSERT INTO documentImports(sourceId, moduleId, majorVersion) "
|
||||
"VALUES (?1, ?2, ?3)",
|
||||
WriteStatement<6> insertDocumentImportWithMajorVersionStatement{
|
||||
"INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
|
||||
"moduleExportedModuleId) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
|
||||
database};
|
||||
WriteStatement<4> insertDocumentImportWithVersionStatement{
|
||||
"INSERT INTO documentImports(sourceId, moduleId, majorVersion, minorVersion) "
|
||||
"VALUES (?1, ?2, ?3, ?4)",
|
||||
WriteStatement<7> insertDocumentImportWithVersionStatement{
|
||||
"INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
|
||||
"minorVersion, moduleExportedModuleId) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
database};
|
||||
WriteStatement<1> deleteDocumentImportStatement{"DELETE FROM documentImports WHERE importId=?1",
|
||||
database};
|
||||
@@ -2426,10 +2617,12 @@ public:
|
||||
"propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT "
|
||||
"NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)",
|
||||
database};
|
||||
ReadStatement<4, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
|
||||
ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
|
||||
"SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
|
||||
"target.propertyDeclarationId FROM propertyDeclarations AS alias JOIN propertyDeclarations "
|
||||
"AS target ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId WHERE "
|
||||
"alias.aliasPropertyDeclarationId, ifnull(alias.aliasPropertyDeclarationTailId, -1) FROM "
|
||||
"propertyDeclarations AS alias JOIN propertyDeclarations AS target ON "
|
||||
"alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR "
|
||||
"alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId WHERE "
|
||||
"alias.propertyTypeId=?1 OR target.typeId=?1 OR alias.propertyImportedTypeNameId IN "
|
||||
"(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) "
|
||||
"WHERE typeId=?1)",
|
||||
@@ -2547,7 +2740,9 @@ public:
|
||||
"SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database};
|
||||
mutable ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{
|
||||
"SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON "
|
||||
"importOrSourceId=importId JOIN exportedTypeNames AS etn USING(moduleId) WHERE "
|
||||
"importOrSourceId=di.importId JOIN documentImports AS di2 ON di.sourceId=di2.sourceId AND "
|
||||
"di.moduleId=di2.sourceModuleId "
|
||||
"JOIN exportedTypeNames AS etn ON di2.moduleId=etn.moduleId WHERE "
|
||||
"itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND "
|
||||
"(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS "
|
||||
"NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, "
|
||||
@@ -2558,8 +2753,8 @@ public:
|
||||
"importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE "
|
||||
"itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND "
|
||||
"(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS "
|
||||
"NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, "
|
||||
"etn.minorVersion DESC NULLS FIRST LIMIT 1",
|
||||
"NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY di.kind, etn.majorVersion DESC "
|
||||
"NULLS FIRST, etn.minorVersion DESC NULLS FIRST LIMIT 1",
|
||||
database};
|
||||
WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database};
|
||||
WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database};
|
||||
@@ -2599,8 +2794,45 @@ public:
|
||||
"SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
|
||||
"projectSourceId=?1",
|
||||
database};
|
||||
ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{
|
||||
mutable ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{
|
||||
"SELECT typeId FROM types WHERE sourceId IN carray(?1)", database};
|
||||
mutable ReadStatement<6, 1> selectModuleExportedImportsForSourceIdStatement{
|
||||
"SELECT moduleExportedImportId, moduleId, exportedModuleId, ifnull(majorVersion, -1), "
|
||||
"ifnull(minorVersion, -1), isAutoVersion FROM moduleExportedImports WHERE moduleId IN "
|
||||
"carray(?1) ORDER BY moduleId, exportedModuleId",
|
||||
database};
|
||||
WriteStatement<3> insertModuleExportedImportWithoutVersionStatement{
|
||||
"INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion) "
|
||||
"VALUES (?1, ?2, ?3)",
|
||||
database};
|
||||
WriteStatement<4> insertModuleExportedImportWithMajorVersionStatement{
|
||||
"INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, "
|
||||
"majorVersion) VALUES (?1, ?2, ?3, ?4)",
|
||||
database};
|
||||
WriteStatement<5> insertModuleExportedImportWithVersionStatement{
|
||||
"INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, "
|
||||
"majorVersion, minorVersion) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
database};
|
||||
WriteStatement<1> deleteModuleExportedImportStatement{
|
||||
"DELETE FROM moduleExportedImports WHERE moduleExportedImportId=?1", database};
|
||||
mutable ReadStatement<4, 3> selectModuleExportedImportsForModuleIdStatement{
|
||||
"WITH RECURSIVE "
|
||||
" imports(moduleId, majorVersion, minorVersion, moduleExportedImportId) AS ( "
|
||||
" SELECT exportedModuleId, "
|
||||
" iif(isAutoVersion=1, ?2, majorVersion), "
|
||||
" iif(isAutoVersion=1, ?3, minorVersion), "
|
||||
" moduleExportedImportId "
|
||||
" FROM moduleExportedImports WHERE moduleId=?1 "
|
||||
" UNION ALL "
|
||||
" SELECT exportedModuleId, "
|
||||
" iif(mei.isAutoVersion=1, i.majorVersion, mei.majorVersion), "
|
||||
" iif(mei.isAutoVersion=1, i.minorVersion, mei.minorVersion), "
|
||||
" mei.moduleExportedImportId "
|
||||
" FROM moduleExportedImports AS mei JOIN imports AS i USING(moduleId)) "
|
||||
"SELECT DISTINCT moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1), "
|
||||
" moduleExportedImportId "
|
||||
"FROM imports",
|
||||
database};
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -77,6 +77,18 @@ public:
|
||||
const char *what() const noexcept override { return "The module does not exist!"; }
|
||||
};
|
||||
|
||||
class ModuleAlreadyExists : std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override { return "The module does already exist!"; }
|
||||
};
|
||||
|
||||
class ExportedTypeCannotBeInserted : std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override { return "The exported type cannot be inserted!"; }
|
||||
};
|
||||
|
||||
class TypeNameDoesNotExists : std::exception
|
||||
{
|
||||
public:
|
||||
|
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 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
|
||||
|
||||
#include "projectstoragetypes.h"
|
||||
|
||||
#include <utils/smallstringio.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
template<auto Type, typename InternalIntergerType = long long>
|
||||
inline QDebug operator<<(QDebug debug, BasicId<Type, InternalIntergerType> id)
|
||||
{
|
||||
debug.noquote() << "(" << id.id << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
namespace QmlDesigner::Storage {
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const Version &version)
|
||||
{
|
||||
debug.noquote() << "(" << version.major.value << ", " << version.minor.value << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const Import &import)
|
||||
{
|
||||
debug.noquote() << "(" << import.moduleId << ", " << import.sourceId << ", " << import.version
|
||||
<< ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const ExportedType &type)
|
||||
{
|
||||
debug.noquote() << "(" << type.name << ", " << type.version << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const QualifiedImportedType &type)
|
||||
{
|
||||
return debug.noquote() << "(" << type.name << ", " << type.import << ")";
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const ImportedType &type)
|
||||
{
|
||||
return debug.noquote() << "(" << type.name << ")";
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const ImportedTypeName &importedTypeName)
|
||||
{
|
||||
std::visit([&](auto &&type) { debug << type; }, importedTypeName);
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const Type &type)
|
||||
{
|
||||
debug.noquote() << "(" << type.typeName << ", " << type.prototype << ", " << type.exportedTypes
|
||||
<< ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner::Storage
|
@@ -34,18 +34,36 @@
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
template<typename Enumeration>
|
||||
constexpr std::underlying_type_t<Enumeration> to_underlying(Enumeration enumeration) noexcept
|
||||
{
|
||||
static_assert(std::is_enum_v<Enumeration>, "to_underlying expect an enumeration");
|
||||
return static_cast<std::underlying_type_t<Enumeration>>(enumeration);
|
||||
}
|
||||
|
||||
using TypeNameString = Utils::BasicSmallString<63>;
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
namespace QmlDesigner::Storage {
|
||||
|
||||
enum class TypeAccessSemantics : int { None, Reference, Value, Sequence, IsEnum = 1 << 8 };
|
||||
|
||||
enum class PropertyDeclarationTraits : unsigned int {
|
||||
constexpr TypeAccessSemantics operator|(TypeAccessSemantics first, TypeAccessSemantics second)
|
||||
{
|
||||
return static_cast<TypeAccessSemantics>(static_cast<int>(first) | static_cast<int>(second));
|
||||
}
|
||||
|
||||
enum class PropertyDeclarationTraits : int {
|
||||
None = 0,
|
||||
IsReadOnly = 1 << 0,
|
||||
IsPointer = 1 << 1,
|
||||
IsList = 1 << 2
|
||||
};
|
||||
|
||||
enum class TypeNameKind { Native = 0, Exported = 1, QualifiedExported = 2 };
|
||||
enum class TypeNameKind { Exported = 1, QualifiedExported = 2 };
|
||||
|
||||
enum class FileType : char { QmlTypes, QmlDocument };
|
||||
|
||||
@@ -136,7 +154,12 @@ inline int operator<(IsQualified first, IsQualified second)
|
||||
return static_cast<int>(first) < static_cast<int>(second);
|
||||
}
|
||||
|
||||
enum class ImportKind : char { Module, Directory, QmlTypesDependency };
|
||||
enum class ImportKind : char {
|
||||
Import,
|
||||
ModuleDependency,
|
||||
ModuleExportedImport,
|
||||
ModuleExportedModuleDependency
|
||||
};
|
||||
|
||||
class Import
|
||||
{
|
||||
@@ -161,11 +184,16 @@ public:
|
||||
&& first.sourceId == second.sourceId;
|
||||
}
|
||||
|
||||
friend bool operator<(const Import &first, const Import &second)
|
||||
{
|
||||
return std::tie(first.sourceId, first.moduleId, first.version)
|
||||
< std::tie(second.sourceId, second.moduleId, second.version);
|
||||
}
|
||||
|
||||
public:
|
||||
Version version;
|
||||
ModuleId moduleId;
|
||||
SourceId sourceId;
|
||||
Utils::SmallString aliasName;
|
||||
};
|
||||
|
||||
using Imports = std::vector<Import>;
|
||||
@@ -195,6 +223,81 @@ public:
|
||||
Version version;
|
||||
};
|
||||
|
||||
enum class IsAutoVersion : char { No, Yes };
|
||||
|
||||
constexpr bool operator<(IsAutoVersion first, IsAutoVersion second)
|
||||
{
|
||||
return to_underlying(first) < to_underlying(second);
|
||||
}
|
||||
|
||||
class ModuleExportedImport
|
||||
{
|
||||
public:
|
||||
explicit ModuleExportedImport(ModuleId moduleId,
|
||||
ModuleId exportedModuleId,
|
||||
Version version,
|
||||
IsAutoVersion isAutoVersion)
|
||||
: version{version}
|
||||
, moduleId{moduleId}
|
||||
, exportedModuleId{exportedModuleId}
|
||||
, isAutoVersion{isAutoVersion}
|
||||
{}
|
||||
|
||||
friend bool operator==(const ModuleExportedImport &first, const ModuleExportedImport &second)
|
||||
{
|
||||
return first.moduleId == second.moduleId && first.version == second.version
|
||||
&& first.exportedModuleId == second.exportedModuleId
|
||||
&& first.isAutoVersion == second.isAutoVersion;
|
||||
}
|
||||
|
||||
friend bool operator<(const ModuleExportedImport &first, const ModuleExportedImport &second)
|
||||
{
|
||||
return std::tie(first.moduleId, first.exportedModuleId, first.isAutoVersion, first.version)
|
||||
< std::tie(second.moduleId, second.exportedModuleId, second.isAutoVersion, second.version);
|
||||
}
|
||||
|
||||
public:
|
||||
Version version;
|
||||
ModuleId moduleId;
|
||||
ModuleId exportedModuleId;
|
||||
IsAutoVersion isAutoVersion = IsAutoVersion::No;
|
||||
};
|
||||
|
||||
using ModuleExportedImports = std::vector<ModuleExportedImport>;
|
||||
|
||||
class ModuleExportedImportView
|
||||
{
|
||||
public:
|
||||
explicit ModuleExportedImportView() = default;
|
||||
|
||||
explicit ModuleExportedImportView(long long moduleExportedImportId,
|
||||
int moduleId,
|
||||
int exportedModuleId,
|
||||
int majorVersion,
|
||||
int minorVersion,
|
||||
int isAutoVersion)
|
||||
: moduleExportedImportId{moduleExportedImportId}
|
||||
, version{majorVersion, minorVersion}
|
||||
, moduleId{moduleId}
|
||||
, exportedModuleId{exportedModuleId}
|
||||
, isAutoVersion{static_cast<IsAutoVersion>(isAutoVersion)}
|
||||
{}
|
||||
|
||||
friend bool operator==(const ModuleExportedImportView &first,
|
||||
const ModuleExportedImportView &second)
|
||||
{
|
||||
return first.moduleId == second.moduleId && first.exportedModuleId == second.exportedModuleId
|
||||
&& first.version == second.version && first.isAutoVersion == second.isAutoVersion;
|
||||
}
|
||||
|
||||
public:
|
||||
ModuleExportedImportId moduleExportedImportId;
|
||||
Version version;
|
||||
ModuleId moduleId;
|
||||
ModuleId exportedModuleId;
|
||||
IsAutoVersion isAutoVersion = IsAutoVersion::No;
|
||||
};
|
||||
|
||||
class ImportedType
|
||||
{
|
||||
public:
|
||||
@@ -209,7 +312,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString name;
|
||||
TypeNameString name;
|
||||
};
|
||||
|
||||
class QualifiedImportedType
|
||||
@@ -227,7 +330,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString name;
|
||||
TypeNameString name;
|
||||
Import import;
|
||||
};
|
||||
|
||||
@@ -266,6 +369,12 @@ public:
|
||||
return first.name == second.name;
|
||||
}
|
||||
|
||||
friend bool operator<(const ExportedType &first, const ExportedType &second)
|
||||
{
|
||||
return std::tie(first.moduleId, first.name, first.version)
|
||||
< std::tie(second.moduleId, second.name, second.version);
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString name;
|
||||
Storage::Version version;
|
||||
@@ -305,24 +414,7 @@ public:
|
||||
ExportedTypeNameId exportedTypeNameId;
|
||||
};
|
||||
|
||||
class NativeType
|
||||
{
|
||||
public:
|
||||
explicit NativeType() = default;
|
||||
explicit NativeType(Utils::SmallStringView name)
|
||||
: name{name}
|
||||
{}
|
||||
|
||||
friend bool operator==(const NativeType &first, const NativeType &second)
|
||||
{
|
||||
return first.name == second.name;
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString name;
|
||||
};
|
||||
|
||||
using ImportedTypeName = Utils::variant<NativeType, ImportedType, QualifiedImportedType>;
|
||||
using ImportedTypeName = Utils::variant<ImportedType, QualifiedImportedType>;
|
||||
|
||||
class EnumeratorDeclaration
|
||||
{
|
||||
@@ -369,7 +461,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString name;
|
||||
TypeNameString name;
|
||||
EnumeratorDeclarations enumeratorDeclarations;
|
||||
};
|
||||
|
||||
@@ -419,7 +511,7 @@ public:
|
||||
|
||||
public:
|
||||
Utils::SmallString name;
|
||||
Utils::SmallString typeName;
|
||||
TypeNameString typeName;
|
||||
PropertyDeclarationTraits traits = {};
|
||||
};
|
||||
|
||||
@@ -494,7 +586,7 @@ public:
|
||||
|
||||
public:
|
||||
Utils::SmallString name;
|
||||
Utils::SmallString returnTypeName;
|
||||
TypeNameString returnTypeName;
|
||||
ParameterDeclarations parameters;
|
||||
};
|
||||
|
||||
@@ -548,10 +640,13 @@ public:
|
||||
explicit PropertyDeclaration(Utils::SmallStringView name,
|
||||
ImportedTypeName typeName,
|
||||
PropertyDeclarationTraits traits,
|
||||
Utils::SmallStringView aliasPropertyName)
|
||||
Utils::SmallStringView aliasPropertyName,
|
||||
Utils::SmallStringView aliasPropertyNameTail = {})
|
||||
: name{name}
|
||||
, typeName{std::move(typeName)}
|
||||
, aliasPropertyName{aliasPropertyName}
|
||||
, aliasPropertyNameTail{aliasPropertyNameTail}
|
||||
|
||||
, traits{traits}
|
||||
, kind{PropertyKind::Property}
|
||||
{}
|
||||
@@ -559,9 +654,11 @@ public:
|
||||
explicit PropertyDeclaration(Utils::SmallStringView name,
|
||||
TypeId propertyTypeId,
|
||||
PropertyDeclarationTraits traits,
|
||||
Utils::SmallStringView aliasPropertyName)
|
||||
Utils::SmallStringView aliasPropertyName,
|
||||
Utils::SmallStringView aliasPropertyNameTail = {})
|
||||
: name{name}
|
||||
, aliasPropertyName{aliasPropertyName}
|
||||
, aliasPropertyNameTail{aliasPropertyNameTail}
|
||||
, traits{traits}
|
||||
, propertyTypeId{propertyTypeId}
|
||||
, kind{PropertyKind::Property}
|
||||
@@ -570,9 +667,12 @@ public:
|
||||
explicit PropertyDeclaration(Utils::SmallStringView name,
|
||||
long long propertyTypeId,
|
||||
int traits,
|
||||
Utils::SmallStringView aliasPropertyName)
|
||||
Utils::SmallStringView aliasPropertyName,
|
||||
Utils::SmallStringView aliasPropertyNameTail = {})
|
||||
: name{name}
|
||||
, aliasPropertyName{aliasPropertyName}
|
||||
, aliasPropertyNameTail{aliasPropertyNameTail}
|
||||
|
||||
, traits{static_cast<PropertyDeclarationTraits>(traits)}
|
||||
, propertyTypeId{propertyTypeId}
|
||||
, kind{PropertyKind::Property}
|
||||
@@ -580,10 +680,13 @@ public:
|
||||
|
||||
explicit PropertyDeclaration(Utils::SmallStringView name,
|
||||
ImportedTypeName aliasTypeName,
|
||||
Utils::SmallStringView aliasPropertyName)
|
||||
Utils::SmallStringView aliasPropertyName,
|
||||
Utils::SmallStringView aliasPropertyNameTail = {})
|
||||
: name{name}
|
||||
, typeName{std::move(aliasTypeName)}
|
||||
, aliasPropertyName{aliasPropertyName}
|
||||
, aliasPropertyNameTail{aliasPropertyNameTail}
|
||||
|
||||
, kind{PropertyKind::Alias}
|
||||
{}
|
||||
|
||||
@@ -591,6 +694,7 @@ public:
|
||||
{
|
||||
return first.name == second.name && first.typeName == second.typeName
|
||||
&& first.aliasPropertyName == second.aliasPropertyName
|
||||
&& first.aliasPropertyNameTail == second.aliasPropertyNameTail
|
||||
&& first.traits == second.traits && first.kind == second.kind;
|
||||
}
|
||||
|
||||
@@ -598,6 +702,7 @@ public:
|
||||
Utils::SmallString name;
|
||||
ImportedTypeName typeName;
|
||||
Utils::SmallString aliasPropertyName;
|
||||
Utils::SmallString aliasPropertyNameTail;
|
||||
PropertyDeclarationTraits traits = {};
|
||||
TypeId propertyTypeId;
|
||||
TypeId typeId;
|
||||
@@ -687,7 +792,7 @@ public:
|
||||
int accessSemantics,
|
||||
int sourceId)
|
||||
: typeName{typeName}
|
||||
, prototype{NativeType{prototype}}
|
||||
, prototype{ImportedType{prototype}}
|
||||
, accessSemantics{static_cast<TypeAccessSemantics>(accessSemantics)}
|
||||
, sourceId{sourceId}
|
||||
|
||||
@@ -716,7 +821,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString typeName;
|
||||
TypeNameString typeName;
|
||||
ImportedTypeName prototype;
|
||||
ExportedTypes exportedTypes;
|
||||
PropertyDeclarations propertyDeclarations;
|
||||
@@ -774,6 +879,18 @@ public:
|
||||
, updatedSourceIds(std::move(updatedSourceIds))
|
||||
{}
|
||||
|
||||
SynchronizationPackage(Imports imports,
|
||||
Types types,
|
||||
SourceIds updatedSourceIds,
|
||||
Imports moduleDependencies,
|
||||
SourceIds updatedModuleDependencySourceIds)
|
||||
: imports{std::move(imports)}
|
||||
, types{std::move(types)}
|
||||
, updatedSourceIds{std::move(updatedSourceIds)}
|
||||
, moduleDependencies{std::move(moduleDependencies)}
|
||||
, updatedModuleDependencySourceIds{std::move(updatedModuleDependencySourceIds)}
|
||||
{}
|
||||
|
||||
SynchronizationPackage(Types types)
|
||||
: types{std::move(types)}
|
||||
{}
|
||||
@@ -800,6 +917,10 @@ public:
|
||||
FileStatuses fileStatuses;
|
||||
ProjectDatas projectDatas;
|
||||
SourceIds updatedProjectSourceIds;
|
||||
Imports moduleDependencies;
|
||||
SourceIds updatedModuleDependencySourceIds;
|
||||
ModuleExportedImports moduleExportedImports;
|
||||
ModuleIds updatedModuleIds;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner::Storage
|
||||
|
@@ -27,19 +27,55 @@
|
||||
|
||||
#include "filestatuscache.h"
|
||||
#include "filesysteminterface.h"
|
||||
#include "projectmanagerinterface.h"
|
||||
#include "projectstorage.h"
|
||||
#include "qmldocumentparserinterface.h"
|
||||
#include "qmltypesparserinterface.h"
|
||||
#include "sourcepath.h"
|
||||
#include "sourcepathcache.h"
|
||||
|
||||
#include <sqlitedatabase.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace {
|
||||
|
||||
QStringList filterMultipleEntries(QStringList qmlTypes)
|
||||
{
|
||||
std::sort(qmlTypes.begin(), qmlTypes.end());
|
||||
qmlTypes.erase(std::unique(qmlTypes.begin(), qmlTypes.end()), qmlTypes.end());
|
||||
|
||||
return qmlTypes;
|
||||
}
|
||||
|
||||
QList<QmlDirParser::Import> filterMultipleEntries(QList<QmlDirParser::Import> imports)
|
||||
{
|
||||
std::stable_sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
|
||||
return first.module < second.module;
|
||||
});
|
||||
imports.erase(std::unique(imports.begin(),
|
||||
imports.end(),
|
||||
[](auto &&first, auto &&second) {
|
||||
return first.module == second.module;
|
||||
}),
|
||||
imports.end());
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
QList<QmlDirParser::Import> joinImports(const QList<QmlDirParser::Import> &firstImports,
|
||||
const QList<QmlDirParser::Import> &secondImports)
|
||||
{
|
||||
QList<QmlDirParser::Import> imports;
|
||||
imports.reserve(firstImports.size() + secondImports.size());
|
||||
imports.append(firstImports);
|
||||
imports.append(secondImports);
|
||||
imports = filterMultipleEntries(std::move(imports));
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
ComponentReferences createComponentReferences(const QMultiHash<QString, QmlDirParser::Component> &components)
|
||||
{
|
||||
ComponentReferences componentReferences;
|
||||
@@ -78,18 +114,108 @@ void addSourceIds(SourceIds &sourceIds, const Storage::ProjectDatas &projectData
|
||||
sourceIds.push_back(projectData.sourceId);
|
||||
}
|
||||
|
||||
Storage::Version convertVersion(LanguageUtils::ComponentVersion version)
|
||||
{
|
||||
return Storage::Version{version.majorVersion(), version.minorVersion()};
|
||||
}
|
||||
|
||||
Storage::IsAutoVersion convertToIsAutoVersion(QmlDirParser::Import::Flags flags)
|
||||
{
|
||||
if (flags & QmlDirParser::Import::Flag::Auto)
|
||||
return Storage::IsAutoVersion::Yes;
|
||||
return Storage::IsAutoVersion::No;
|
||||
}
|
||||
|
||||
void addDependencies(Storage::Imports &dependencies,
|
||||
SourceId sourceId,
|
||||
const QList<QmlDirParser::Import> &qmldirDependencies,
|
||||
ProjectStorageInterface &projectStorage)
|
||||
{
|
||||
for (const QmlDirParser::Import &qmldirDependency : qmldirDependencies) {
|
||||
ModuleId moduleId = projectStorage.moduleId(Utils::PathString{qmldirDependency.module}
|
||||
+ "-cppnative");
|
||||
dependencies.emplace_back(moduleId, Storage::Version{}, sourceId);
|
||||
}
|
||||
}
|
||||
|
||||
void addModuleExportedImports(Storage::ModuleExportedImports &imports,
|
||||
ModuleId moduleId,
|
||||
ModuleId cppModuleId,
|
||||
const QList<QmlDirParser::Import> &qmldirImports,
|
||||
ProjectStorageInterface &projectStorage)
|
||||
{
|
||||
for (const QmlDirParser::Import &qmldirImport : qmldirImports) {
|
||||
ModuleId exportedModuleId = projectStorage.moduleId(Utils::PathString{qmldirImport.module});
|
||||
imports.emplace_back(moduleId,
|
||||
exportedModuleId,
|
||||
convertVersion(qmldirImport.version),
|
||||
convertToIsAutoVersion(qmldirImport.flags));
|
||||
|
||||
ModuleId exportedCppModuleId = projectStorage.moduleId(
|
||||
Utils::PathString{qmldirImport.module} + "-cppnative");
|
||||
imports.emplace_back(cppModuleId,
|
||||
exportedCppModuleId,
|
||||
Storage::Version{},
|
||||
Storage::IsAutoVersion::No);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ProjectUpdater::update()
|
||||
void ProjectStorageUpdater::update(QStringList qmlDirs, QStringList qmlTypesPaths)
|
||||
{
|
||||
Storage::SynchronizationPackage package;
|
||||
|
||||
SourceIds notUpdatedFileStatusSourceIds;
|
||||
SourceIds notUpdatedSourceIds;
|
||||
|
||||
for (const QString &qmldirPath : m_projectManager.qtQmlDirs()) {
|
||||
updateQmldirs(qmlDirs, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
|
||||
updateQmlTypes(qmlTypesPaths, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
|
||||
|
||||
package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
|
||||
std::move(notUpdatedSourceIds));
|
||||
package.updatedFileStatusSourceIds = filterNotUpdatedSourceIds(
|
||||
std::move(package.updatedFileStatusSourceIds), std::move(notUpdatedFileStatusSourceIds));
|
||||
|
||||
m_projectStorage.synchronize(std::move(package));
|
||||
}
|
||||
|
||||
void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds)
|
||||
{
|
||||
if (qmlTypesPaths.empty())
|
||||
return;
|
||||
|
||||
ModuleId moduleId = m_projectStorage.moduleId("QML-cppnative");
|
||||
|
||||
for (const QString &qmlTypesPath : qmlTypesPaths) {
|
||||
SourceId sourceId = m_pathCache.sourceId(SourcePath{qmlTypesPath});
|
||||
|
||||
Storage::ProjectData projectData{sourceId, sourceId, moduleId, Storage::FileType::QmlTypes};
|
||||
|
||||
FileState state = parseTypeInfo(projectData,
|
||||
Utils::PathString{qmlTypesPath},
|
||||
package,
|
||||
notUpdatedFileStatusSourceIds,
|
||||
notUpdatedSourceIds);
|
||||
|
||||
if (state == FileState::Changed)
|
||||
package.projectDatas.push_back(std::move(projectData));
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectStorageUpdater::updateQmldirs(const QStringList &qmlDirs,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds)
|
||||
{
|
||||
for (const QString &qmldirPath : qmlDirs) {
|
||||
SourcePath qmldirSourcePath{qmldirPath};
|
||||
SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath);
|
||||
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
|
||||
Utils::PathString directoryPath = m_pathCache.sourceContextPath(directoryId);
|
||||
|
||||
auto state = fileState(qmlDirSourceId,
|
||||
package.fileStatuses,
|
||||
@@ -102,26 +228,43 @@ void ProjectUpdater::update()
|
||||
|
||||
package.updatedSourceIds.push_back(qmlDirSourceId);
|
||||
|
||||
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
|
||||
|
||||
Utils::PathString moduleName{parser.typeNamespace()};
|
||||
ModuleId moduleId = m_projectStorage.moduleId(moduleName);
|
||||
ModuleId cppModuleId = m_projectStorage.moduleId(moduleName + "-cppnative");
|
||||
ModuleId pathModuleId = m_projectStorage.moduleId(directoryPath);
|
||||
|
||||
auto imports = filterMultipleEntries(parser.imports());
|
||||
|
||||
addModuleExportedImports(package.moduleExportedImports,
|
||||
moduleId,
|
||||
cppModuleId,
|
||||
imports,
|
||||
m_projectStorage);
|
||||
package.updatedModuleIds.push_back(moduleId);
|
||||
|
||||
const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
|
||||
addSourceIds(package.updatedSourceIds, qmlProjectDatas);
|
||||
addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas);
|
||||
|
||||
parseTypeInfos(parser.typeInfos(),
|
||||
qmlDirSourceId,
|
||||
directoryId,
|
||||
moduleId,
|
||||
package,
|
||||
notUpdatedFileStatusSourceIds,
|
||||
notUpdatedSourceIds);
|
||||
auto qmlTypes = filterMultipleEntries(parser.typeInfos());
|
||||
|
||||
if (!qmlTypes.isEmpty()) {
|
||||
parseTypeInfos(qmlTypes,
|
||||
filterMultipleEntries(parser.dependencies()),
|
||||
imports,
|
||||
qmlDirSourceId,
|
||||
directoryPath,
|
||||
cppModuleId,
|
||||
package,
|
||||
notUpdatedFileStatusSourceIds,
|
||||
notUpdatedSourceIds);
|
||||
}
|
||||
parseQmlComponents(createComponentReferences(parser.components()),
|
||||
qmlDirSourceId,
|
||||
directoryId,
|
||||
moduleId,
|
||||
pathModuleId,
|
||||
package,
|
||||
notUpdatedFileStatusSourceIds);
|
||||
package.updatedProjectSourceIds.push_back(qmlDirSourceId);
|
||||
@@ -130,7 +273,7 @@ void ProjectUpdater::update()
|
||||
case FileState::NotChanged: {
|
||||
const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
|
||||
parseTypeInfos(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
|
||||
parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds);
|
||||
parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, directoryPath);
|
||||
break;
|
||||
}
|
||||
case FileState::NotExists: {
|
||||
@@ -144,30 +287,31 @@ void ProjectUpdater::update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
|
||||
std::move(notUpdatedSourceIds));
|
||||
package.updatedFileStatusSourceIds = filterNotUpdatedSourceIds(
|
||||
std::move(package.updatedFileStatusSourceIds), std::move(notUpdatedFileStatusSourceIds));
|
||||
|
||||
m_projectStorage.synchronize(std::move(package));
|
||||
}
|
||||
|
||||
void ProjectUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) {}
|
||||
void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) {}
|
||||
|
||||
void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
|
||||
SourceId qmldirSourceId,
|
||||
SourceContextId directoryId,
|
||||
ModuleId moduleId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds)
|
||||
void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
|
||||
const QList<QmlDirParser::Import> &qmldirDependencies,
|
||||
const QList<QmlDirParser::Import> &qmldirImports,
|
||||
SourceId qmldirSourceId,
|
||||
Utils::SmallStringView directoryPath,
|
||||
ModuleId moduleId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds)
|
||||
{
|
||||
QString directory{m_pathCache.sourceContextPath(directoryId)};
|
||||
|
||||
for (const QString &typeInfo : typeInfos) {
|
||||
SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo});
|
||||
QString qmltypesPath = directory + "/" + typeInfo;
|
||||
Utils::PathString qmltypesPath = Utils::PathString::join(
|
||||
{directoryPath, "/", Utils::SmallString{typeInfo}});
|
||||
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmltypesPath});
|
||||
|
||||
addDependencies(package.moduleDependencies,
|
||||
sourceId,
|
||||
joinImports(qmldirDependencies, qmldirImports),
|
||||
m_projectStorage);
|
||||
package.updatedModuleDependencySourceIds.push_back(sourceId);
|
||||
|
||||
auto projectData = package.projectDatas.emplace_back(qmldirSourceId,
|
||||
sourceId,
|
||||
@@ -182,16 +326,16 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds)
|
||||
void ProjectStorageUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds)
|
||||
{
|
||||
for (const Storage::ProjectData &projectData : projectDatas) {
|
||||
if (projectData.fileType != Storage::FileType::QmlTypes)
|
||||
continue;
|
||||
|
||||
QString qmltypesPath = m_pathCache.sourcePath(projectData.sourceId).toQString();
|
||||
auto qmltypesPath = m_pathCache.sourcePath(projectData.sourceId);
|
||||
|
||||
parseTypeInfo(projectData,
|
||||
qmltypesPath,
|
||||
@@ -201,11 +345,11 @@ void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
|
||||
const QString &qmltypesPath,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds)
|
||||
auto ProjectStorageUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
|
||||
Utils::SmallStringView qmltypesPath,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds) -> FileState
|
||||
{
|
||||
auto state = fileState(projectData.sourceId,
|
||||
package.fileStatuses,
|
||||
@@ -215,7 +359,7 @@ void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
|
||||
case FileState::Changed: {
|
||||
package.updatedSourceIds.push_back(projectData.sourceId);
|
||||
|
||||
const auto content = m_fileSystem.contentAsQString(qmltypesPath);
|
||||
const auto content = m_fileSystem.contentAsQString(QString{qmltypesPath});
|
||||
m_qmlTypesParser.parse(content, package.imports, package.types, projectData);
|
||||
break;
|
||||
}
|
||||
@@ -226,19 +370,23 @@ void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
|
||||
case FileState::NotExists:
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
|
||||
Utils::SmallStringView directory,
|
||||
Utils::SmallStringView typeName,
|
||||
Storage::Version version,
|
||||
ModuleId moduleId,
|
||||
SourceId qmldirSourceId,
|
||||
SourceContextId directoryId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds)
|
||||
void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFilePath,
|
||||
Utils::SmallStringView directoryPath,
|
||||
Storage::ExportedTypes exportedTypes,
|
||||
ModuleId moduleId,
|
||||
SourceId qmldirSourceId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds)
|
||||
{
|
||||
SourceId sourceId = m_pathCache.sourceId(directoryId, fileName);
|
||||
if (std::find(relativeFilePath.begin(), relativeFilePath.end(), '+') != relativeFilePath.end())
|
||||
return;
|
||||
|
||||
Utils::PathString qmlFilePath = Utils::PathString::join({directoryPath, "/", relativeFilePath});
|
||||
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmlFilePath});
|
||||
|
||||
Storage::Type type;
|
||||
|
||||
@@ -253,9 +401,8 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
|
||||
case FileState::NotExists:
|
||||
throw CannotParseQmlDocumentFile{};
|
||||
case FileState::Changed:
|
||||
const auto content = m_fileSystem.contentAsQString(
|
||||
QString{Utils::PathString{directory} + "/" + fileName});
|
||||
type = m_qmlDocumentParser.parse(content, package.imports);
|
||||
const auto content = m_fileSystem.contentAsQString(QString{qmlFilePath});
|
||||
type = m_qmlDocumentParser.parse(content, package.imports, sourceId, directoryPath);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -263,19 +410,20 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
|
||||
|
||||
package.updatedSourceIds.push_back(sourceId);
|
||||
|
||||
type.typeName = fileName;
|
||||
type.typeName = SourcePath{qmlFilePath}.name();
|
||||
type.accessSemantics = Storage::TypeAccessSemantics::Reference;
|
||||
type.sourceId = sourceId;
|
||||
type.exportedTypes.push_back(Storage::ExportedType{moduleId, typeName, version});
|
||||
type.exportedTypes = std::move(exportedTypes);
|
||||
|
||||
package.types.push_back(std::move(type));
|
||||
}
|
||||
|
||||
void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
|
||||
Utils::SmallStringView filePath,
|
||||
SourceId sourceId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds)
|
||||
void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView fileName,
|
||||
Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView directoryPath,
|
||||
SourceId sourceId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds)
|
||||
{
|
||||
auto state = fileState(sourceId,
|
||||
package.fileStatuses,
|
||||
@@ -286,8 +434,10 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
|
||||
|
||||
package.updatedSourceIds.push_back(sourceId);
|
||||
|
||||
SourcePath sourcePath{filePath};
|
||||
|
||||
const auto content = m_fileSystem.contentAsQString(QString{filePath});
|
||||
auto type = m_qmlDocumentParser.parse(content, package.imports);
|
||||
auto type = m_qmlDocumentParser.parse(content, package.imports, sourceId, directoryPath);
|
||||
|
||||
type.typeName = fileName;
|
||||
type.accessSemantics = Storage::TypeAccessSemantics::Reference;
|
||||
@@ -297,43 +447,111 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
|
||||
package.types.push_back(std::move(type));
|
||||
}
|
||||
|
||||
void ProjectUpdater::parseQmlComponents(ComponentReferences components,
|
||||
SourceId qmldirSourceId,
|
||||
SourceContextId directoryId,
|
||||
ModuleId moduleId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds)
|
||||
namespace {
|
||||
|
||||
class ComponentReferencesRange
|
||||
{
|
||||
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
|
||||
return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion)
|
||||
> std::tie(second.get().typeName, second.get().majorVersion, second.get().minorVersion);
|
||||
});
|
||||
public:
|
||||
using const_iterator = ComponentReferences::const_iterator;
|
||||
|
||||
auto newEnd = std::unique(components.begin(), components.end(), [](auto &&first, auto &&second) {
|
||||
return first.get().typeName == second.get().typeName
|
||||
&& first.get().majorVersion == second.get().majorVersion;
|
||||
});
|
||||
ComponentReferencesRange(const_iterator begin, const_iterator end)
|
||||
: m_begin{begin}
|
||||
, m_end{end}
|
||||
{}
|
||||
|
||||
components.erase(newEnd, components.end());
|
||||
std::size_t size() const { return static_cast<std::size_t>(std::distance(m_begin, m_end)); }
|
||||
|
||||
auto directory = m_pathCache.sourceContextPath(directoryId);
|
||||
const_iterator begin() const { return m_begin; }
|
||||
const_iterator end() const { return m_end; }
|
||||
|
||||
for (const QmlDirParser::Component &component : components) {
|
||||
parseQmlComponent(Utils::SmallString{component.fileName},
|
||||
directory,
|
||||
Utils::SmallString{component.typeName},
|
||||
Storage::Version{component.majorVersion, component.minorVersion},
|
||||
moduleId,
|
||||
qmldirSourceId,
|
||||
directoryId,
|
||||
package,
|
||||
notUpdatedFileStatusSourceIds);
|
||||
private:
|
||||
const_iterator m_begin;
|
||||
const_iterator m_end;
|
||||
};
|
||||
|
||||
template<typename Callback>
|
||||
void partitionForTheSameFileName(const ComponentReferences &components, Callback callback)
|
||||
{
|
||||
auto current = components.begin();
|
||||
const auto end = components.end();
|
||||
|
||||
while (current != end) {
|
||||
auto nextType = std::partition_point(current, end, [&](const auto &component) {
|
||||
return component.get().fileName == current->get().fileName;
|
||||
});
|
||||
|
||||
callback(ComponentReferencesRange{current, nextType});
|
||||
|
||||
current = nextType;
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds)
|
||||
Storage::ExportedTypes createExportedTypes(ComponentReferencesRange components,
|
||||
ModuleId moduleId,
|
||||
Utils::SmallStringView fileName,
|
||||
ModuleId pathModuleId)
|
||||
{
|
||||
Storage::ExportedTypes exportedTypes;
|
||||
exportedTypes.reserve(components.size() + 1);
|
||||
|
||||
for (ComponentReference component : components) {
|
||||
exportedTypes.emplace_back(moduleId,
|
||||
Utils::SmallString{component.get().typeName},
|
||||
Storage::Version{component.get().majorVersion,
|
||||
component.get().minorVersion});
|
||||
}
|
||||
|
||||
auto foundDot = std::find(fileName.begin(), fileName.end(), '.');
|
||||
|
||||
exportedTypes.emplace_back(pathModuleId,
|
||||
Utils::SmallStringView{fileName.begin(), foundDot},
|
||||
Storage::Version{});
|
||||
|
||||
return exportedTypes;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ProjectStorageUpdater::parseQmlComponents(ComponentReferences components,
|
||||
SourceId qmldirSourceId,
|
||||
SourceContextId directoryId,
|
||||
ModuleId moduleId,
|
||||
ModuleId pathModuleId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds)
|
||||
{
|
||||
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
|
||||
return std::tie(first.get().fileName,
|
||||
first.get().typeName,
|
||||
first.get().majorVersion,
|
||||
first.get().minorVersion)
|
||||
> std::tie(first.get().fileName,
|
||||
second.get().typeName,
|
||||
second.get().majorVersion,
|
||||
second.get().minorVersion);
|
||||
});
|
||||
|
||||
auto directoryPath = m_pathCache.sourceContextPath(directoryId);
|
||||
|
||||
auto callback = [&](ComponentReferencesRange componentsWithSameFileName) {
|
||||
const auto &firstComponent = *componentsWithSameFileName.begin();
|
||||
const Utils::SmallString fileName{firstComponent.get().fileName};
|
||||
parseQmlComponent(fileName,
|
||||
directoryPath,
|
||||
createExportedTypes(componentsWithSameFileName, moduleId, fileName, pathModuleId),
|
||||
moduleId,
|
||||
qmldirSourceId,
|
||||
package,
|
||||
notUpdatedFileStatusSourceIds);
|
||||
};
|
||||
|
||||
partitionForTheSameFileName(components, callback);
|
||||
}
|
||||
|
||||
void ProjectStorageUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
Utils::SmallStringView directoryPath)
|
||||
{
|
||||
for (const Storage::ProjectData &projectData : projectDatas) {
|
||||
if (projectData.fileType != Storage::FileType::QmlDocument)
|
||||
@@ -343,16 +561,17 @@ void ProjectUpdater::parseQmlComponents(const Storage::ProjectDatas &projectData
|
||||
|
||||
parseQmlComponent(qmlDocumentPath.name(),
|
||||
qmlDocumentPath,
|
||||
directoryPath,
|
||||
projectData.sourceId,
|
||||
package,
|
||||
notUpdatedFileStatusSourceIds);
|
||||
}
|
||||
}
|
||||
|
||||
ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId,
|
||||
FileStatuses &fileStatuses,
|
||||
SourceIds &updatedSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds) const
|
||||
ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState(SourceId sourceId,
|
||||
FileStatuses &fileStatuses,
|
||||
SourceIds &updatedSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds) const
|
||||
{
|
||||
auto currentFileStatus = m_fileStatusCache.find(sourceId);
|
||||
|
||||
|
@@ -42,7 +42,6 @@ class Database;
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
class ProjectManagerInterface;
|
||||
class FileSystemInterface;
|
||||
class ProjectStorageInterface;
|
||||
template<typename ProjectStorage, typename Mutex>
|
||||
@@ -53,22 +52,21 @@ class ProjectStorage;
|
||||
class QmlDocumentParserInterface;
|
||||
class QmlTypesParserInterface;
|
||||
|
||||
using ComponentReferences = std::vector<std::reference_wrapper<const QmlDirParser::Component>>;
|
||||
using ComponentReference = std::reference_wrapper<const QmlDirParser::Component>;
|
||||
using ComponentReferences = std::vector<ComponentReference>;
|
||||
|
||||
class ProjectUpdater
|
||||
class ProjectStorageUpdater
|
||||
{
|
||||
public:
|
||||
using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>;
|
||||
|
||||
ProjectUpdater(ProjectManagerInterface &projectManager,
|
||||
FileSystemInterface &fileSystem,
|
||||
ProjectStorageInterface &projectStorage,
|
||||
FileStatusCache &fileStatusCache,
|
||||
PathCache &pathCache,
|
||||
QmlDocumentParserInterface &qmlDocumentParser,
|
||||
QmlTypesParserInterface &qmlTypesParser)
|
||||
: m_projectManager{projectManager}
|
||||
, m_fileSystem{fileSystem}
|
||||
ProjectStorageUpdater(FileSystemInterface &fileSystem,
|
||||
ProjectStorageInterface &projectStorage,
|
||||
FileStatusCache &fileStatusCache,
|
||||
PathCache &pathCache,
|
||||
QmlDocumentParserInterface &qmlDocumentParser,
|
||||
QmlTypesParserInterface &qmlTypesParser)
|
||||
: m_fileSystem{fileSystem}
|
||||
, m_projectStorage{projectStorage}
|
||||
, m_fileStatusCache{fileStatusCache}
|
||||
, m_pathCache{pathCache}
|
||||
@@ -76,7 +74,7 @@ public:
|
||||
, m_qmlTypesParser{qmlTypesParser}
|
||||
{}
|
||||
|
||||
void update();
|
||||
void update(QStringList qmlDirs, QStringList qmlTypesPaths);
|
||||
void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths);
|
||||
|
||||
private:
|
||||
@@ -86,9 +84,20 @@ private:
|
||||
NotExists,
|
||||
};
|
||||
|
||||
void updateQmlTypes(const QStringList &qmlTypesPaths,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds);
|
||||
void updateQmldirs(const QStringList &qmlDirs,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds);
|
||||
|
||||
void parseTypeInfos(const QStringList &typeInfos,
|
||||
const QList<QmlDirParser::Import> &qmldirDependencies,
|
||||
const QList<QmlDirParser::Import> &qmldirImports,
|
||||
SourceId qmldirSourceId,
|
||||
SourceContextId directoryId,
|
||||
Utils::SmallStringView directoryPath,
|
||||
ModuleId moduleId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
@@ -97,31 +106,32 @@ private:
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds);
|
||||
void parseTypeInfo(const Storage::ProjectData &projectData,
|
||||
const QString &qmltypesPath,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds);
|
||||
FileState parseTypeInfo(const Storage::ProjectData &projectData,
|
||||
Utils::SmallStringView qmltypesPath,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
SourceIds ¬UpdatedSourceIds);
|
||||
void parseQmlComponents(ComponentReferences components,
|
||||
SourceId qmldirSourceId,
|
||||
SourceContextId directoryId,
|
||||
ModuleId moduleId,
|
||||
ModuleId pathModuleId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds);
|
||||
void parseQmlComponents(const Storage::ProjectDatas &projectDatas,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds);
|
||||
SourceIds ¬UpdatedFileStatusSourceIds,
|
||||
Utils::SmallStringView directoryPath);
|
||||
void parseQmlComponent(Utils::SmallStringView fileName,
|
||||
Utils::SmallStringView directory,
|
||||
Utils::SmallStringView typeName,
|
||||
Storage::Version version,
|
||||
Storage::ExportedTypes exportedTypes,
|
||||
ModuleId moduleId,
|
||||
SourceId qmldirSourceId,
|
||||
SourceContextId directoryId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds);
|
||||
void parseQmlComponent(Utils::SmallStringView fileName,
|
||||
Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView directoryPath,
|
||||
SourceId sourceId,
|
||||
Storage::SynchronizationPackage &package,
|
||||
SourceIds ¬UpdatedFileStatusSourceIds);
|
||||
@@ -132,7 +142,6 @@ private:
|
||||
SourceIds ¬UpdatedSourceIds) const;
|
||||
|
||||
private:
|
||||
ProjectManagerInterface &m_projectManager;
|
||||
FileSystemInterface &m_fileSystem;
|
||||
ProjectStorageInterface &m_projectStorage;
|
||||
FileStatusCache &m_fileStatusCache;
|
||||
|
@@ -1,3 +1,4 @@
|
||||
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
@@ -26,6 +27,7 @@
|
||||
#include "qmldocumentparser.h"
|
||||
|
||||
#include "projectstorage.h"
|
||||
#include "projectstorageexceptions.h"
|
||||
#include "sourcepathcache.h"
|
||||
|
||||
#include <sqlitedatabase.h>
|
||||
@@ -45,6 +47,8 @@ namespace QmlDom = QQmlJS::Dom;
|
||||
|
||||
namespace {
|
||||
|
||||
using QualifiedImports = std::map<QString, Storage::Import>;
|
||||
|
||||
int convertVersionNumber(qint32 versionNumber)
|
||||
{
|
||||
return versionNumber < 0 ? -1 : versionNumber;
|
||||
@@ -56,46 +60,189 @@ Storage::Version convertVersion(QmlDom::Version version)
|
||||
convertVersionNumber(version.minorVersion)};
|
||||
}
|
||||
|
||||
Utils::PathString convertUri(const QString &uri)
|
||||
Utils::PathString createNormalizedPath(Utils::SmallStringView directoryPath,
|
||||
const QString &relativePath)
|
||||
{
|
||||
QStringView localPath{uri.begin() + 7, uri.end()};
|
||||
std::filesystem::path modulePath{std::string_view{directoryPath},
|
||||
std::filesystem::path::format::generic_format};
|
||||
|
||||
std::filesystem::path path{
|
||||
std::u16string_view{localPath.utf16(), static_cast<std::size_t>(localPath.size())}};
|
||||
modulePath /= relativePath.toStdString();
|
||||
|
||||
auto x = std::filesystem::weakly_canonical(path);
|
||||
Utils::PathString normalizedPath = modulePath.lexically_normal().generic_string();
|
||||
|
||||
return Utils::PathString{x.generic_string()};
|
||||
if (normalizedPath[normalizedPath.size() - 1] == '/')
|
||||
normalizedPath.resize(normalizedPath.size() - 1);
|
||||
|
||||
return normalizedPath;
|
||||
}
|
||||
|
||||
Storage::Import createImport(const QmlDom::Import &qmlImport,
|
||||
SourceId sourceId,
|
||||
Utils::SmallStringView directoryPath,
|
||||
QmlDocumentParser::ProjectStorage &storage)
|
||||
{
|
||||
using QmlUriKind = QQmlJS::Dom::QmlUri::Kind;
|
||||
|
||||
auto &&uri = qmlImport.uri;
|
||||
|
||||
if (uri.kind() == QmlUriKind::RelativePath) {
|
||||
auto path = createNormalizedPath(directoryPath, uri.localPath());
|
||||
auto moduleId = storage.moduleId(createNormalizedPath(directoryPath, uri.localPath()));
|
||||
return Storage::Import(moduleId, Storage::Version{}, sourceId);
|
||||
}
|
||||
|
||||
if (uri.kind() == QmlUriKind::ModuleUri) {
|
||||
auto moduleId = storage.moduleId(Utils::PathString{uri.moduleUri()});
|
||||
return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId);
|
||||
}
|
||||
|
||||
auto moduleId = storage.moduleId(Utils::PathString{uri.toString()});
|
||||
return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId);
|
||||
}
|
||||
|
||||
QualifiedImports createQualifiedImports(const QList<QmlDom::Import> &qmlImports,
|
||||
SourceId sourceId,
|
||||
Utils::SmallStringView directoryPath,
|
||||
QmlDocumentParser::ProjectStorage &storage)
|
||||
{
|
||||
QualifiedImports qualifiedImports;
|
||||
|
||||
for (const QmlDom::Import &qmlImport : qmlImports) {
|
||||
if (!qmlImport.importId.isEmpty() && !qmlImport.implicit)
|
||||
qualifiedImports.try_emplace(qmlImport.importId,
|
||||
createImport(qmlImport, sourceId, directoryPath, storage));
|
||||
}
|
||||
|
||||
return qualifiedImports;
|
||||
}
|
||||
|
||||
void addImports(Storage::Imports &imports,
|
||||
const QList<QmlDom::Import> &qmlImports,
|
||||
SourceId sourceId,
|
||||
const QString &directoryPath,
|
||||
Utils::SmallStringView directoryPath,
|
||||
QmlDocumentParser::ProjectStorage &storage)
|
||||
{
|
||||
int importCount = 0;
|
||||
for (const QmlDom::Import &qmlImport : qmlImports) {
|
||||
if (qmlImport.uri == u"file://.") {
|
||||
auto moduleId = storage.moduleId(Utils::PathString{directoryPath});
|
||||
imports.emplace_back(moduleId, Storage::Version{}, sourceId);
|
||||
} else if (qmlImport.uri.startsWith(u"file://")) {
|
||||
auto x = convertUri(qmlImport.uri);
|
||||
auto moduleId = storage.moduleId(convertUri(qmlImport.uri));
|
||||
imports.emplace_back(moduleId, Storage::Version{}, sourceId);
|
||||
} else {
|
||||
auto moduleId = storage.moduleId(Utils::SmallString{qmlImport.uri});
|
||||
imports.emplace_back(moduleId, convertVersion(qmlImport.version), sourceId);
|
||||
if (!qmlImport.implicit) {
|
||||
imports.push_back(createImport(qmlImport, sourceId, directoryPath, storage));
|
||||
++importCount;
|
||||
}
|
||||
}
|
||||
|
||||
auto localDirectoryModuleId = storage.moduleId(directoryPath);
|
||||
imports.emplace_back(localDirectoryModuleId, Storage::Version{}, sourceId);
|
||||
++importCount;
|
||||
|
||||
auto qmlModuleId = storage.moduleId("QML");
|
||||
imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId);
|
||||
++importCount;
|
||||
|
||||
auto end = imports.end();
|
||||
auto begin = std::prev(end, importCount);
|
||||
|
||||
std::sort(begin, end);
|
||||
imports.erase(std::unique(begin, end), end);
|
||||
}
|
||||
|
||||
void addPropertyDeclarations(Storage::Type &type, const QmlDom::QmlObject &rootObject)
|
||||
Storage::ImportedTypeName createImportedTypeName(const QStringView rawtypeName,
|
||||
const QualifiedImports &qualifiedImports)
|
||||
{
|
||||
auto foundDot = std::find(rawtypeName.begin(), rawtypeName.end(), '.');
|
||||
|
||||
QStringView alias(rawtypeName.begin(), foundDot);
|
||||
|
||||
auto foundImport = qualifiedImports.find(alias.toString());
|
||||
if (foundImport == qualifiedImports.end())
|
||||
return Storage::ImportedType{Utils::SmallString{rawtypeName}};
|
||||
|
||||
QStringView typeName(std::next(foundDot), rawtypeName.end());
|
||||
|
||||
return Storage::QualifiedImportedType{Utils::SmallString{typeName.toString()},
|
||||
foundImport->second};
|
||||
}
|
||||
|
||||
bool isListProperty(const QStringView rawtypeName)
|
||||
{
|
||||
return rawtypeName.startsWith(u"list<") && rawtypeName.endsWith(u'>');
|
||||
}
|
||||
|
||||
struct TypeNameViewAndTraits
|
||||
{
|
||||
QStringView typeName;
|
||||
Storage::PropertyDeclarationTraits traits;
|
||||
};
|
||||
|
||||
TypeNameViewAndTraits filteredListTypeName(const QStringView rawtypeName)
|
||||
{
|
||||
if (!isListProperty(rawtypeName))
|
||||
return {rawtypeName, Storage::PropertyDeclarationTraits::None};
|
||||
|
||||
return {rawtypeName.mid(5, rawtypeName.size() - 6), Storage::PropertyDeclarationTraits::IsList};
|
||||
};
|
||||
|
||||
struct TypeNameAndTraits
|
||||
{
|
||||
Storage::ImportedTypeName importedTypeName;
|
||||
Storage::PropertyDeclarationTraits traits;
|
||||
};
|
||||
|
||||
TypeNameAndTraits createImportedTypeNameAndTypeTraits(const QStringView rawtypeName,
|
||||
const QualifiedImports &qualifiedImports)
|
||||
{
|
||||
auto [filteredTypeName, traits] = filteredListTypeName(rawtypeName);
|
||||
|
||||
if (!filteredTypeName.contains('.'))
|
||||
return {Storage::ImportedType{Utils::SmallString{filteredTypeName}}, traits};
|
||||
|
||||
return {createImportedTypeName(filteredTypeName, qualifiedImports), traits};
|
||||
}
|
||||
|
||||
std::pair<Utils::SmallString, Utils::SmallString> createAccessPaths(const QStringList &accessPath)
|
||||
{
|
||||
if (accessPath.size() == 1)
|
||||
return {accessPath[0], {}};
|
||||
|
||||
if (accessPath.size() == 2)
|
||||
return {accessPath[0], accessPath[1]};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void addPropertyDeclarations(Storage::Type &type,
|
||||
QmlDom::QmlObject &rootObject,
|
||||
const QualifiedImports &qualifiedImports,
|
||||
QmlDom::DomItem &fileItem)
|
||||
{
|
||||
for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) {
|
||||
type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
|
||||
Storage::ImportedType{
|
||||
Utils::SmallString{propertyDeclaration.typeName}},
|
||||
Storage::PropertyDeclarationTraits::None);
|
||||
if (propertyDeclaration.isAlias()) {
|
||||
auto rootObjectItem = fileItem.copy(&rootObject);
|
||||
auto property = rootObjectItem.bindings()
|
||||
.key(propertyDeclaration.name)
|
||||
.index(0)
|
||||
.field(QmlDom::Fields::value);
|
||||
auto resolvedAlias = rootObject.resolveAlias(rootObjectItem,
|
||||
property.ownerAs<QmlDom::ScriptExpression>());
|
||||
if (resolvedAlias.valid()) {
|
||||
auto [aliasPropertyName, aliasPropertyNameTail] = createAccessPaths(
|
||||
resolvedAlias.accessedPath);
|
||||
|
||||
auto [importedTypeName, traits] = createImportedTypeNameAndTypeTraits(
|
||||
resolvedAlias.typeName, qualifiedImports);
|
||||
|
||||
type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
|
||||
std::move(importedTypeName),
|
||||
traits,
|
||||
aliasPropertyName,
|
||||
aliasPropertyNameTail);
|
||||
}
|
||||
} else {
|
||||
auto [importedTypeName, traits] = createImportedTypeNameAndTypeTraits(
|
||||
propertyDeclaration.typeName, qualifiedImports);
|
||||
type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
|
||||
std::move(importedTypeName),
|
||||
traits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,18 +294,20 @@ void addEnumeraton(Storage::Type &type, const QmlDom::Component &component)
|
||||
Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
|
||||
Storage::Imports &imports,
|
||||
SourceId sourceId,
|
||||
const QString &directoryPath)
|
||||
Utils::SmallStringView directoryPath)
|
||||
{
|
||||
Storage::Type type;
|
||||
|
||||
QmlDom::DomItem environment = QmlDom::DomEnvironment::create(
|
||||
{},
|
||||
QmlDom::DomEnvironment::Option::SingleThreaded
|
||||
| QmlDom::DomEnvironment::Option::NoDependencies);
|
||||
using Option = QmlDom::DomEnvironment::Option;
|
||||
|
||||
QmlDom::DomItem environment = QmlDom::DomEnvironment::create({},
|
||||
Option::SingleThreaded
|
||||
| Option::NoDependencies
|
||||
| Option::WeakLoad);
|
||||
|
||||
QmlDom::DomItem items;
|
||||
|
||||
QString filePath{directoryPath + "/foo.qml"};
|
||||
QString filePath{m_pathCache.sourcePath(sourceId)};
|
||||
|
||||
environment.loadFile(
|
||||
filePath,
|
||||
@@ -181,18 +330,25 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
|
||||
return type;
|
||||
|
||||
const auto &component = components.first();
|
||||
const auto &objects = component.objects();
|
||||
auto objects = component.objects();
|
||||
|
||||
if (objects.empty())
|
||||
return type;
|
||||
|
||||
const QmlDom::QmlObject &qmlObject = objects.front();
|
||||
QmlDom::QmlObject &qmlObject = objects.front();
|
||||
|
||||
type.prototype = Storage::ImportedType{Utils::SmallString{qmlObject.name()}};
|
||||
const auto qmlImports = qmlFile->imports();
|
||||
|
||||
const auto qualifiedImports = createQualifiedImports(qmlImports,
|
||||
sourceId,
|
||||
directoryPath,
|
||||
m_storage);
|
||||
|
||||
type.prototype = createImportedTypeName(qmlObject.name(), qualifiedImports);
|
||||
|
||||
addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
|
||||
|
||||
addPropertyDeclarations(type, qmlObject);
|
||||
addPropertyDeclarations(type, qmlObject, qualifiedImports, file);
|
||||
addFunctionAndSignalDeclarations(type, qmlObject);
|
||||
addEnumeraton(type, component);
|
||||
|
||||
|
@@ -40,22 +40,24 @@ class ProjectStorage;
|
||||
template<typename ProjectStorage, typename Mutex>
|
||||
class SourcePathCache;
|
||||
|
||||
class QmlDocumentParser
|
||||
class QmlDocumentParser : public QmlDocumentParserInterface
|
||||
{
|
||||
public:
|
||||
using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
|
||||
using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>;
|
||||
|
||||
QmlDocumentParser(ProjectStorage &storage)
|
||||
QmlDocumentParser(ProjectStorage &storage, PathCache &pathCache)
|
||||
: m_storage{storage}
|
||||
, m_pathCache{pathCache}
|
||||
{}
|
||||
|
||||
Storage::Type parse(const QString &sourceContent,
|
||||
Storage::Imports &imports,
|
||||
SourceId sourceId,
|
||||
const QString &directoryPath);
|
||||
Utils::SmallStringView directoryPath) override;
|
||||
|
||||
private:
|
||||
ProjectStorage &m_storage;
|
||||
PathCache &m_pathCache;
|
||||
};
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -34,7 +34,11 @@ namespace QmlDesigner {
|
||||
class QmlDocumentParserInterface
|
||||
{
|
||||
public:
|
||||
virtual Storage::Type parse(const QString &sourceContent, Storage::Imports &imports) = 0;
|
||||
virtual Storage::Type parse(const QString &sourceContent,
|
||||
Storage::Imports &imports,
|
||||
SourceId sourceId,
|
||||
Utils::SmallStringView directoryPath)
|
||||
= 0;
|
||||
|
||||
protected:
|
||||
~QmlDocumentParserInterface() = default;
|
||||
|
@@ -47,6 +47,29 @@ namespace QmlDom = QQmlJS::Dom;
|
||||
|
||||
namespace {
|
||||
|
||||
using ComponentWithoutNamespaces = QMap<QString, QString>;
|
||||
|
||||
ComponentWithoutNamespaces createComponentNameWithoutNamespaces(
|
||||
const QHash<QString, QQmlJSExportedScope> &objects)
|
||||
{
|
||||
ComponentWithoutNamespaces componentWithoutNamespaces;
|
||||
|
||||
for (auto current = objects.keyBegin(), end = objects.keyEnd(); current != end; ++current) {
|
||||
const QString &key = *current;
|
||||
QString searchTerm{"::"};
|
||||
|
||||
auto found = std::search(key.cbegin(), key.cend(), searchTerm.cbegin(), searchTerm.cend());
|
||||
|
||||
if (found == key.cend())
|
||||
continue;
|
||||
|
||||
componentWithoutNamespaces.insert(QStringView{std::next(found, 2), key.cend()}.toString(),
|
||||
key);
|
||||
}
|
||||
|
||||
return componentWithoutNamespaces;
|
||||
}
|
||||
|
||||
void appendImports(Storage::Imports &imports,
|
||||
const QString &dependency,
|
||||
SourceId sourceId,
|
||||
@@ -60,43 +83,22 @@ void appendImports(Storage::Imports &imports,
|
||||
moduleName.append("-cppnative");
|
||||
ModuleId cppModuleId = storage.moduleId(moduleName);
|
||||
|
||||
auto majorVersionFound = std::find_if(spaceFound, dependency.end(), [](QChar c) {
|
||||
return c.isDigit();
|
||||
});
|
||||
auto majorVersionEnd = std::find_if(majorVersionFound, dependency.end(), [](QChar c) {
|
||||
return !c.isDigit();
|
||||
});
|
||||
|
||||
Storage::Version version;
|
||||
|
||||
QStringView majorVersionString(majorVersionFound, majorVersionEnd);
|
||||
if (!majorVersionString.isEmpty()) {
|
||||
version.major.value = majorVersionString.toInt();
|
||||
|
||||
auto minorVersionFound = std::find_if(majorVersionEnd, dependency.end(), [](QChar c) {
|
||||
return c.isDigit();
|
||||
});
|
||||
auto minorVersionEnd = std::find_if(minorVersionFound, dependency.end(), [](QChar c) {
|
||||
return !c.isDigit();
|
||||
});
|
||||
QStringView minorVersionString(minorVersionFound, minorVersionEnd);
|
||||
if (!minorVersionString.isEmpty())
|
||||
version.minor.value = QStringView(minorVersionFound, minorVersionEnd).toInt();
|
||||
}
|
||||
|
||||
imports.emplace_back(cppModuleId, version, sourceId);
|
||||
imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
|
||||
}
|
||||
|
||||
void addImports(Storage::Imports &imports,
|
||||
SourceId sourceId,
|
||||
const QStringList &dependencies,
|
||||
QmlTypesParser::ProjectStorage &storage)
|
||||
QmlTypesParser::ProjectStorage &storage,
|
||||
ModuleId cppModuleId)
|
||||
{
|
||||
for (const QString &dependency : dependencies)
|
||||
appendImports(imports, dependency, sourceId, storage);
|
||||
|
||||
imports.emplace_back(storage.moduleId("QML"), Storage::Version{}, sourceId);
|
||||
imports.emplace_back(storage.moduleId("QtQml-cppnative"), Storage::Version{}, sourceId);
|
||||
imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
|
||||
|
||||
if (ModuleId qmlCppModuleId = storage.moduleId("QML-cppnative"); cppModuleId != qmlCppModuleId)
|
||||
imports.emplace_back(qmlCppModuleId, Storage::Version{}, sourceId);
|
||||
}
|
||||
|
||||
Storage::TypeAccessSemantics createTypeAccessSemantics(QQmlJSScope::AccessSemantics accessSematics)
|
||||
@@ -121,7 +123,7 @@ Storage::Version createVersion(QTypeRevision qmlVersion)
|
||||
}
|
||||
|
||||
Storage::ExportedTypes createExports(const QList<QQmlJSScope::Export> &qmlExports,
|
||||
const QQmlJSScope &component,
|
||||
Utils::SmallStringView interanalName,
|
||||
QmlTypesParser::ProjectStorage &storage,
|
||||
ModuleId cppModuleId)
|
||||
{
|
||||
@@ -129,12 +131,43 @@ Storage::ExportedTypes createExports(const QList<QQmlJSScope::Export> &qmlExport
|
||||
exportedTypes.reserve(Utils::usize(qmlExports));
|
||||
|
||||
for (const QQmlJSScope::Export &qmlExport : qmlExports) {
|
||||
TypeNameString exportedTypeName{qmlExport.type()};
|
||||
exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}),
|
||||
Utils::SmallString{qmlExport.type()},
|
||||
std::move(exportedTypeName),
|
||||
createVersion(qmlExport.version()));
|
||||
}
|
||||
|
||||
exportedTypes.emplace_back(cppModuleId, Utils::SmallString{component.internalName()});
|
||||
TypeNameString cppExportedTypeName{interanalName};
|
||||
exportedTypes.emplace_back(cppModuleId, cppExportedTypeName);
|
||||
|
||||
return exportedTypes;
|
||||
}
|
||||
|
||||
auto createCppEnumerationExport(Utils::SmallStringView typeName, Utils::SmallStringView enumerationName)
|
||||
{
|
||||
TypeNameString cppExportedTypeName{typeName};
|
||||
cppExportedTypeName += "::";
|
||||
cppExportedTypeName += enumerationName;
|
||||
|
||||
return cppExportedTypeName;
|
||||
}
|
||||
|
||||
Storage::ExportedTypes createCppEnumerationExports(Utils::SmallStringView typeName,
|
||||
ModuleId cppModuleId,
|
||||
Utils::SmallStringView enumerationName,
|
||||
Utils::SmallStringView enumerationAlias)
|
||||
{
|
||||
Storage::ExportedTypes exportedTypes;
|
||||
|
||||
if (!enumerationAlias.empty()) {
|
||||
exportedTypes.reserve(2);
|
||||
exportedTypes.emplace_back(cppModuleId,
|
||||
createCppEnumerationExport(typeName, enumerationAlias));
|
||||
} else {
|
||||
exportedTypes.reserve(1);
|
||||
}
|
||||
|
||||
exportedTypes.emplace_back(cppModuleId, createCppEnumerationExport(typeName, enumerationName));
|
||||
|
||||
return exportedTypes;
|
||||
}
|
||||
@@ -155,22 +188,61 @@ Storage::PropertyDeclarationTraits createPropertyDeclarationTraits(const QQmlJSM
|
||||
return traits;
|
||||
}
|
||||
|
||||
Storage::PropertyDeclarations createProperties(const QHash<QString, QQmlJSMetaProperty> &qmlProperties)
|
||||
struct EnumerationType
|
||||
{
|
||||
EnumerationType(Utils::SmallStringView name, Utils::SmallStringView full)
|
||||
: name{name}
|
||||
, full{full}
|
||||
{}
|
||||
|
||||
Utils::SmallString name;
|
||||
TypeNameString full;
|
||||
};
|
||||
|
||||
using EnumerationTypes = std::vector<EnumerationType>;
|
||||
|
||||
TypeNameString fullyQualifiedTypeName(const QString &typeName,
|
||||
const ComponentWithoutNamespaces &componentNameWithoutNamespace)
|
||||
{
|
||||
if (auto found = componentNameWithoutNamespace.find(typeName);
|
||||
found != componentNameWithoutNamespace.end())
|
||||
return found.value();
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
Storage::PropertyDeclarations createProperties(
|
||||
const QHash<QString, QQmlJSMetaProperty> &qmlProperties,
|
||||
const EnumerationTypes &enumerationTypes,
|
||||
const ComponentWithoutNamespaces &componentNameWithoutNamespace)
|
||||
{
|
||||
Storage::PropertyDeclarations propertyDeclarations;
|
||||
propertyDeclarations.reserve(Utils::usize(qmlProperties));
|
||||
|
||||
for (const QQmlJSMetaProperty &qmlProperty : qmlProperties) {
|
||||
if (qmlProperty.typeName().isEmpty())
|
||||
continue;
|
||||
|
||||
TypeNameString propertyTypeName{
|
||||
fullyQualifiedTypeName(qmlProperty.typeName(), componentNameWithoutNamespace)};
|
||||
|
||||
auto found = find_if(enumerationTypes.begin(), enumerationTypes.end(), [&](auto &entry) {
|
||||
return entry.name == propertyTypeName;
|
||||
});
|
||||
|
||||
if (found != enumerationTypes.end())
|
||||
propertyTypeName = found->full;
|
||||
|
||||
propertyDeclarations.emplace_back(Utils::SmallString{qmlProperty.propertyName()},
|
||||
Storage::NativeType{
|
||||
Utils::SmallString{qmlProperty.typeName()}},
|
||||
Storage::ImportedType{propertyTypeName},
|
||||
createPropertyDeclarationTraits(qmlProperty));
|
||||
}
|
||||
|
||||
return propertyDeclarations;
|
||||
}
|
||||
|
||||
Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMethod)
|
||||
Storage::ParameterDeclarations createParameters(
|
||||
const QQmlJSMetaMethod &qmlMethod, const ComponentWithoutNamespaces &componentNameWithoutNamespace)
|
||||
{
|
||||
Storage::ParameterDeclarations parameterDeclarations;
|
||||
|
||||
@@ -183,14 +255,16 @@ Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMetho
|
||||
|
||||
for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) {
|
||||
parameterDeclarations.emplace_back(Utils::SmallString{*currentName},
|
||||
Utils::SmallString{*currentType});
|
||||
fullyQualifiedTypeName(*currentType,
|
||||
componentNameWithoutNamespace));
|
||||
}
|
||||
|
||||
return parameterDeclarations;
|
||||
}
|
||||
|
||||
std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFunctionAndSignals(
|
||||
const QMultiHash<QString, QQmlJSMetaMethod> &qmlMethods)
|
||||
const QMultiHash<QString, QQmlJSMetaMethod> &qmlMethods,
|
||||
const ComponentWithoutNamespaces &componentNameWithoutNamespace)
|
||||
{
|
||||
std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> functionAndSignalDeclarations;
|
||||
Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)};
|
||||
@@ -199,13 +273,18 @@ std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFun
|
||||
signalDeclarations.reserve(Utils::usize(qmlMethods));
|
||||
|
||||
for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) {
|
||||
if (qmlMethod.isJavaScriptFunction())
|
||||
continue;
|
||||
|
||||
if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) {
|
||||
functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()},
|
||||
Utils::SmallString{qmlMethod.returnTypeName()},
|
||||
createParameters(qmlMethod));
|
||||
fullyQualifiedTypeName(qmlMethod.returnTypeName(),
|
||||
componentNameWithoutNamespace),
|
||||
createParameters(qmlMethod,
|
||||
componentNameWithoutNamespace));
|
||||
} else {
|
||||
signalDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()},
|
||||
createParameters(qmlMethod));
|
||||
createParameters(qmlMethod, componentNameWithoutNamespace));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,40 +332,130 @@ Storage::EnumerationDeclarations createEnumeration(const QHash<QString, QQmlJSMe
|
||||
enumerationDeclarations.reserve(Utils::usize(qmlEnumerations));
|
||||
|
||||
for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) {
|
||||
enumerationDeclarations.emplace_back(Utils::SmallString{qmlEnumeration.name()},
|
||||
enumerationDeclarations.emplace_back(TypeNameString{qmlEnumeration.name()},
|
||||
createEnumerators(qmlEnumeration));
|
||||
}
|
||||
|
||||
return enumerationDeclarations;
|
||||
}
|
||||
|
||||
auto addEnumerationType(EnumerationTypes &enumerationTypes,
|
||||
Utils::SmallStringView typeName,
|
||||
Utils::SmallStringView enumerationName)
|
||||
{
|
||||
auto fullTypeName = TypeNameString::join({typeName, "::", enumerationName});
|
||||
enumerationTypes.emplace_back(enumerationName, std::move(fullTypeName));
|
||||
|
||||
return fullTypeName;
|
||||
}
|
||||
|
||||
void addEnumerationType(EnumerationTypes &enumerationTypes,
|
||||
Storage::Types &types,
|
||||
Utils::SmallStringView typeName,
|
||||
Utils::SmallStringView enumerationName,
|
||||
SourceId sourceId,
|
||||
ModuleId cppModuleId,
|
||||
Utils::SmallStringView enumerationAlias)
|
||||
{
|
||||
auto fullTypeName = addEnumerationType(enumerationTypes, typeName, enumerationName);
|
||||
types.emplace_back(fullTypeName,
|
||||
Storage::ImportedType{TypeNameString{}},
|
||||
Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum,
|
||||
sourceId,
|
||||
createCppEnumerationExports(typeName,
|
||||
cppModuleId,
|
||||
enumerationName,
|
||||
enumerationAlias));
|
||||
|
||||
if (!enumerationAlias.empty())
|
||||
addEnumerationType(enumerationTypes, typeName, enumerationAlias);
|
||||
}
|
||||
|
||||
QSet<QString> createEnumerationAliases(const QHash<QString, QQmlJSMetaEnum> &qmlEnumerations)
|
||||
{
|
||||
QSet<QString> aliases;
|
||||
|
||||
for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) {
|
||||
if (auto &&alias = qmlEnumeration.alias(); !alias.isEmpty())
|
||||
aliases.insert(alias);
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
|
||||
EnumerationTypes addEnumerationTypes(Storage::Types &types,
|
||||
Utils::SmallStringView typeName,
|
||||
SourceId sourceId,
|
||||
ModuleId cppModuleId,
|
||||
const QHash<QString, QQmlJSMetaEnum> &qmlEnumerations)
|
||||
{
|
||||
EnumerationTypes enumerationTypes;
|
||||
enumerationTypes.reserve(Utils::usize(qmlEnumerations));
|
||||
|
||||
QSet<QString> aliases = createEnumerationAliases(qmlEnumerations);
|
||||
|
||||
for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) {
|
||||
if (aliases.contains(qmlEnumeration.name()))
|
||||
continue;
|
||||
|
||||
TypeNameString enumerationName{qmlEnumeration.name()};
|
||||
TypeNameString enumerationAlias{qmlEnumeration.alias()};
|
||||
addEnumerationType(enumerationTypes,
|
||||
types,
|
||||
typeName,
|
||||
enumerationName,
|
||||
sourceId,
|
||||
cppModuleId,
|
||||
enumerationAlias);
|
||||
}
|
||||
|
||||
return enumerationTypes;
|
||||
}
|
||||
|
||||
void addType(Storage::Types &types,
|
||||
SourceId sourceId,
|
||||
ModuleId cppModuleId,
|
||||
const QQmlJSScope &component,
|
||||
QmlTypesParser::ProjectStorage &storage)
|
||||
const QQmlJSExportedScope &exportScope,
|
||||
QmlTypesParser::ProjectStorage &storage,
|
||||
const ComponentWithoutNamespaces &componentNameWithoutNamespace)
|
||||
{
|
||||
auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(component.ownMethods());
|
||||
types.emplace_back(Utils::SmallString{component.internalName()},
|
||||
Storage::NativeType{Utils::SmallString{component.baseTypeName()}},
|
||||
const auto &component = *exportScope.scope;
|
||||
|
||||
auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(
|
||||
component.ownMethods(), componentNameWithoutNamespace);
|
||||
TypeNameString typeName{component.internalName()};
|
||||
auto enumerations = component.ownEnumerations();
|
||||
auto exports = exportScope.exports;
|
||||
|
||||
auto enumerationTypes = addEnumerationTypes(types, typeName, sourceId, cppModuleId, enumerations);
|
||||
types.emplace_back(Utils::SmallStringView{typeName},
|
||||
Storage::ImportedType{TypeNameString{component.baseTypeName()}},
|
||||
createTypeAccessSemantics(component.accessSemantics()),
|
||||
sourceId,
|
||||
createExports(component.exports(), component, storage, cppModuleId),
|
||||
createProperties(component.ownProperties()),
|
||||
createExports(exports, typeName, storage, cppModuleId),
|
||||
createProperties(component.ownProperties(),
|
||||
enumerationTypes,
|
||||
componentNameWithoutNamespace),
|
||||
std::move(functionsDeclarations),
|
||||
std::move(signalDeclarations),
|
||||
createEnumeration(component.ownEnumerations()));
|
||||
createEnumeration(enumerations));
|
||||
}
|
||||
|
||||
void addTypes(Storage::Types &types,
|
||||
const Storage::ProjectData &projectData,
|
||||
const QHash<QString, QQmlJSScope::Ptr> &objects,
|
||||
QmlTypesParser::ProjectStorage &storage)
|
||||
const QHash<QString, QQmlJSExportedScope> &objects,
|
||||
QmlTypesParser::ProjectStorage &storage,
|
||||
const ComponentWithoutNamespaces &componentNameWithoutNamespaces)
|
||||
{
|
||||
types.reserve(Utils::usize(objects) + types.size());
|
||||
|
||||
for (const auto &object : objects)
|
||||
addType(types, projectData.sourceId, projectData.moduleId, *object.get(), storage);
|
||||
addType(types,
|
||||
projectData.sourceId,
|
||||
projectData.moduleId,
|
||||
object,
|
||||
storage,
|
||||
componentNameWithoutNamespaces);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -297,14 +466,16 @@ void QmlTypesParser::parse(const QString &sourceContent,
|
||||
const Storage::ProjectData &projectData)
|
||||
{
|
||||
QQmlJSTypeDescriptionReader reader({}, sourceContent);
|
||||
QHash<QString, QQmlJSScope::Ptr> components;
|
||||
QHash<QString, QQmlJSExportedScope> components;
|
||||
QStringList dependencies;
|
||||
bool isValid = reader(&components, &dependencies);
|
||||
if (!isValid)
|
||||
throw CannotParseQmlTypesFile{};
|
||||
|
||||
addImports(imports, projectData.sourceId, dependencies, m_storage);
|
||||
addTypes(types, projectData, components, m_storage);
|
||||
auto componentNameWithoutNamespaces = createComponentNameWithoutNamespaces(components);
|
||||
|
||||
addImports(imports, projectData.sourceId, dependencies, m_storage, projectData.moduleId);
|
||||
addTypes(types, projectData, components, m_storage, componentNameWithoutNamespaces);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@@ -121,15 +121,43 @@ public:
|
||||
Sqlite::JournalMode::Wal,
|
||||
Sqlite::LockingMode::Normal};
|
||||
ImageCacheStorage<Sqlite::Database> storage{database};
|
||||
ImageCacheConnectionManager connectionManager;
|
||||
ImageCacheCollector collector{connectionManager,
|
||||
QSize{300, 300},
|
||||
QSize{1000, 1000},
|
||||
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
|
||||
TimeStampProvider timeStampProvider;
|
||||
AsynchronousExplicitImageCache cache{storage};
|
||||
AsynchronousImageFactory factory{storage, timeStampProvider, collector};
|
||||
};
|
||||
|
||||
class ProjectStorageData
|
||||
{
|
||||
public:
|
||||
ProjectStorageData(::ProjectExplorer::Project *project)
|
||||
: database{project->projectDirectory().pathAppended("projectstorage.db").toString()}
|
||||
{}
|
||||
|
||||
Sqlite::Database database;
|
||||
ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
|
||||
ProjectStorageUpdater::PathCache pathCache{storage};
|
||||
FileSystem fileSystem{pathCache};
|
||||
FileStatusCache fileStatusCache{fileSystem};
|
||||
QmlDocumentParser qmlDocumentParser{storage, pathCache};
|
||||
QmlTypesParser qmlTypesParser{pathCache, storage};
|
||||
ProjectStorageUpdater updater{
|
||||
fileSystem, storage, fileStatusCache, pathCache, qmlDocumentParser, qmlTypesParser};
|
||||
};
|
||||
|
||||
class QmlDesignerProjectManager::QmlDesignerProjectManagerProjectData
|
||||
{
|
||||
public:
|
||||
QmlDesignerProjectManagerProjectData(ImageCacheStorage<Sqlite::Database> &storage)
|
||||
QmlDesignerProjectManagerProjectData(ImageCacheStorage<Sqlite::Database> &storage,
|
||||
::ProjectExplorer::Project *project)
|
||||
: factory{storage, timeStampProvider, collector}
|
||||
, projectStorageData{project}
|
||||
{}
|
||||
|
||||
ImageCacheConnectionManager connectionManager;
|
||||
ImageCacheCollector collector{connectionManager,
|
||||
QSize{300, 300},
|
||||
@@ -137,6 +165,7 @@ public:
|
||||
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
|
||||
TimeStampProvider timeStampProvider;
|
||||
AsynchronousImageFactory factory;
|
||||
ProjectStorageData projectStorageData;
|
||||
::ProjectExplorer::Target *activeTarget = nullptr;
|
||||
};
|
||||
|
||||
@@ -191,23 +220,154 @@ void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *)
|
||||
m_projectData->activeTarget);
|
||||
|
||||
if (qmlBuildSystem) {
|
||||
m_projectData->collector.setTarget(m_projectData->activeTarget);
|
||||
m_projectData->factory.generate(qmlBuildSystem->mainFilePath().toString().toUtf8());
|
||||
m_previewImageCacheData->collector.setTarget(m_projectData->activeTarget);
|
||||
m_previewImageCacheData->factory.generate(qmlBuildSystem->mainFilePath().toString().toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::editorsClosed(const QList<::Core::IEditor *> &) {}
|
||||
|
||||
namespace {
|
||||
|
||||
QtSupport::QtVersion *getQtVersion(::ProjectExplorer::Target *target)
|
||||
{
|
||||
if (target)
|
||||
return QtSupport::QtKitAspect::qtVersion(target->kit());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QtSupport::QtVersion *getQtVersion(::ProjectExplorer::Project *project)
|
||||
{
|
||||
return getQtVersion(project->activeTarget());
|
||||
}
|
||||
|
||||
Utils::FilePath qmlPath(::ProjectExplorer::Target *target)
|
||||
{
|
||||
auto qt = QtSupport::QtKitAspect::qtVersion(target->kit());
|
||||
if (qt)
|
||||
return qt->qmlPath();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void projectQmldirPaths(::ProjectExplorer::Target *target, QStringList &qmldirPaths)
|
||||
{
|
||||
::QmlProjectManager::QmlBuildSystem *buildSystem = getQmlBuildSystem(target);
|
||||
|
||||
const Utils::FilePath pojectDirectoryPath = buildSystem->canonicalProjectDir();
|
||||
const QStringList importPaths = buildSystem->importPaths();
|
||||
const QDir pojectDirectory(pojectDirectoryPath.toString());
|
||||
|
||||
for (const QString &importPath : importPaths)
|
||||
qmldirPaths.push_back(QDir::cleanPath(pojectDirectory.absoluteFilePath(importPath))
|
||||
+ "/qmldir");
|
||||
}
|
||||
|
||||
bool skipPath(const std::filesystem::path &path)
|
||||
{
|
||||
auto directory = path.filename();
|
||||
qDebug() << path.string().data();
|
||||
|
||||
bool skip = directory == "QtApplicationManager" || directory == "QtInterfaceFramework"
|
||||
|| directory == "QtOpcUa" || directory == "Qt3D" || directory == "Qt3D"
|
||||
|| directory == "Scene2D" || directory == "Scene3D" || directory == "QtWayland"
|
||||
|| directory == "Qt5Compat";
|
||||
if (skip)
|
||||
qDebug() << "skip" << path.string().data();
|
||||
|
||||
return skip;
|
||||
}
|
||||
|
||||
void qtQmldirPaths(::ProjectExplorer::Target *target, QStringList &qmldirPaths)
|
||||
{
|
||||
const QString installDirectory = qmlPath(target).toString();
|
||||
|
||||
const std::filesystem::path installDirectoryPath{installDirectory.toStdString()};
|
||||
|
||||
auto current = std::filesystem::recursive_directory_iterator{installDirectoryPath};
|
||||
auto end = std::filesystem::end(current);
|
||||
for (; current != end; ++current) {
|
||||
const auto &entry = *current;
|
||||
auto path = entry.path();
|
||||
if (current.depth() < 3 && !current->is_regular_file() && skipPath(path)) {
|
||||
current.disable_recursion_pending();
|
||||
continue;
|
||||
}
|
||||
if (path.filename() == "qmldir") {
|
||||
qmldirPaths.push_back(QString::fromStdU16String(path.generic_u16string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList qmlDirs(::ProjectExplorer::Target *target)
|
||||
{
|
||||
if (!target)
|
||||
return {};
|
||||
|
||||
QStringList qmldirPaths;
|
||||
qmldirPaths.reserve(100);
|
||||
|
||||
qtQmldirPaths(target, qmldirPaths);
|
||||
projectQmldirPaths(target, qmldirPaths);
|
||||
|
||||
std::sort(qmldirPaths.begin(), qmldirPaths.end());
|
||||
qmldirPaths.erase(std::unique(qmldirPaths.begin(), qmldirPaths.end()), qmldirPaths.end());
|
||||
|
||||
return qmldirPaths;
|
||||
}
|
||||
|
||||
QStringList qmlTypes(::ProjectExplorer::Target *target)
|
||||
{
|
||||
if (!target)
|
||||
return {};
|
||||
|
||||
QStringList qmldirPaths;
|
||||
qmldirPaths.reserve(2);
|
||||
|
||||
const QString installDirectory = qmlPath(target).toString();
|
||||
|
||||
qmldirPaths.append(installDirectory + "/builtins.qmltypes");
|
||||
qmldirPaths.append(installDirectory + "/jsroot.qmltypes");
|
||||
|
||||
qmldirPaths.append(
|
||||
Core::ICore::resourcePath("qmldesigner/projectstorage/fake.qmltypes").toString());
|
||||
|
||||
return qmldirPaths;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project)
|
||||
{
|
||||
m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_previewImageCacheData->storage);
|
||||
m_projectData->activeTarget = project->activeTarget();
|
||||
if (qEnvironmentVariableIsSet("QDS_ACTIVATE_PROJECT_STORAGE")) {
|
||||
m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_previewImageCacheData->storage,
|
||||
project);
|
||||
m_projectData->activeTarget = project->activeTarget();
|
||||
|
||||
QObject::connect(project, &::ProjectExplorer::Project::fileListChanged, [&]() {
|
||||
fileListChanged();
|
||||
});
|
||||
|
||||
QObject::connect(project,
|
||||
&::ProjectExplorer::Project::activeTargetChanged,
|
||||
[&](auto *target) { activeTargetChanged(target); });
|
||||
|
||||
QObject::connect(project,
|
||||
&::ProjectExplorer::Project::aboutToRemoveTarget,
|
||||
[&](auto *target) { aboutToRemoveTarget(target); });
|
||||
|
||||
if (auto target = project->activeTarget(); target)
|
||||
activeTargetChanged(target);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::aboutToRemoveProject(::ProjectExplorer::Project *)
|
||||
{
|
||||
if (m_projectData)
|
||||
if (m_projectData) {
|
||||
m_previewImageCacheData->collector.setTarget(m_projectData->activeTarget);
|
||||
m_projectData.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::projectRemoved(::ProjectExplorer::Project *) {}
|
||||
@@ -244,4 +404,56 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache
|
||||
return m_imageCacheData.get();
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::fileListChanged()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::activeTargetChanged(ProjectExplorer::Target *target)
|
||||
{
|
||||
if (m_projectData)
|
||||
return;
|
||||
|
||||
QObject::disconnect(m_projectData->activeTarget, nullptr, nullptr, nullptr);
|
||||
|
||||
m_projectData->activeTarget = target;
|
||||
|
||||
if (target) {
|
||||
QObject::connect(target, &::ProjectExplorer::Target::kitChanged, [&]() { kitChanged(); });
|
||||
QObject::connect(getQmlBuildSystem(target),
|
||||
&::QmlProjectManager::QmlBuildSystem::projectChanged,
|
||||
[&]() { projectChanged(); });
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::aboutToRemoveTarget(ProjectExplorer::Target *target)
|
||||
{
|
||||
QObject::disconnect(target, nullptr, nullptr, nullptr);
|
||||
QObject::disconnect(getQmlBuildSystem(target), nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::kitChanged()
|
||||
{
|
||||
QStringList qmldirPaths;
|
||||
qmldirPaths.reserve(100);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::projectChanged()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void QmlDesignerProjectManager::update()
|
||||
{
|
||||
if (!m_projectData)
|
||||
return;
|
||||
|
||||
m_projectData->projectStorageData.updater.update(qmlDirs(m_projectData->activeTarget),
|
||||
qmlTypes(m_projectData->activeTarget));
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -69,6 +69,15 @@ private:
|
||||
void projectRemoved(::ProjectExplorer::Project *project);
|
||||
ImageCacheData *imageCacheData();
|
||||
|
||||
void fileListChanged();
|
||||
void activeTargetChanged(::ProjectExplorer::Target *target);
|
||||
void aboutToRemoveTarget(::ProjectExplorer::Target *target);
|
||||
void kitChanged();
|
||||
void projectChanged();
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
private:
|
||||
std::once_flag imageCacheFlag;
|
||||
std::unique_ptr<ImageCacheData> m_imageCacheData;
|
||||
|
@@ -327,6 +327,8 @@ void QmlBuildSystem::refresh(RefreshOptions options)
|
||||
modelManager->updateProjectInfo(projectInfo, project());
|
||||
|
||||
guard.markAsSuccess();
|
||||
|
||||
emit projectChanged();
|
||||
}
|
||||
|
||||
QString QmlBuildSystem::mainFile() const
|
||||
@@ -749,6 +751,20 @@ QStringList QmlBuildSystem::shaderToolFiles() const
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList QmlBuildSystem::importPaths() const
|
||||
{
|
||||
if (m_projectItem)
|
||||
return m_projectItem->importPaths();
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList QmlBuildSystem::files() const
|
||||
{
|
||||
if (m_projectItem)
|
||||
return m_projectItem->files();
|
||||
return {};
|
||||
}
|
||||
|
||||
bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *)
|
||||
{
|
||||
if (!dynamic_cast<QmlProjectNode *>(context))
|
||||
|
@@ -103,6 +103,8 @@ public:
|
||||
bool widgetApp() const;
|
||||
QStringList shaderToolArgs() const;
|
||||
QStringList shaderToolFiles() const;
|
||||
QStringList importPaths() const;
|
||||
QStringList files() const;
|
||||
|
||||
bool addFiles(const QStringList &filePaths);
|
||||
|
||||
@@ -121,6 +123,9 @@ public:
|
||||
// plain format
|
||||
void parseProject(RefreshOptions options);
|
||||
|
||||
signals:
|
||||
void projectChanged();
|
||||
|
||||
private:
|
||||
bool setFileSettingInProjectFile(const QString &setting,
|
||||
const Utils::FilePath &mainFilePath,
|
||||
|
@@ -265,7 +265,6 @@ extend_qtc_test(unittest
|
||||
projectstorage/filestatus.h
|
||||
projectstorage/filestatuscache.cpp projectstorage/filestatuscache.h
|
||||
projectstorage/nonlockingmutex.h
|
||||
projectstorage/projectmanagerinterface.h
|
||||
projectstorage/projectstorageinterface.h
|
||||
projectstorage/projectstorage.h
|
||||
projectstorage/projectstoragepathwatcher.h
|
||||
@@ -301,7 +300,6 @@ extend_qtc_test(unittest
|
||||
filesystemmock.h
|
||||
filestatuscache-test.cpp
|
||||
listmodeleditor-test.cpp
|
||||
projectmanagermock.h
|
||||
projectstorage-test.cpp
|
||||
projectstorageupdater-test.cpp
|
||||
projectstoragesqlitefunctionregistry-test.cpp
|
||||
@@ -378,25 +376,29 @@ get_filename_component(
|
||||
ABSOLUTE
|
||||
)
|
||||
|
||||
if(EXISTS ${QMLDOM_STANDALONE_CMAKELISTS} AND Qt6_FOUND)
|
||||
if(EXISTS ${QMLDOM_STANDALONE_CMAKELISTS} AND Qt6_FOUND AND NOT TARGET qmldomlib)
|
||||
add_subdirectory(
|
||||
../../../../qmldom_standalone/src/qmldom/standalone
|
||||
${CMAKE_CURRENT_BINARY_DIR}/qmldom_standalone)
|
||||
${CMAKE_BINARY_DIR}/qmldom_standalone)
|
||||
|
||||
set_target_properties(qmldomlib PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,RUNTIME_OUTPUT_DIRECTORY>"
|
||||
LIBRARY_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,LIBRARY_OUTPUT_DIRECTORY>")
|
||||
|
||||
extend_qtc_test(unittest
|
||||
DEPENDS qmldomlib
|
||||
SOURCES
|
||||
qmldocumentparser-test.cpp
|
||||
qmltypesparser-test.cpp
|
||||
)
|
||||
extend_qtc_test(unittest
|
||||
SOURCES_PREFIX "${QmlDesignerDir}/designercore"
|
||||
SOURCES
|
||||
projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h
|
||||
projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h
|
||||
)
|
||||
endif()
|
||||
|
||||
extend_qtc_test(unittest
|
||||
CONDITION TARGET qmldomlib
|
||||
DEPENDS qmldomlib
|
||||
SOURCES
|
||||
qmldocumentparser-test.cpp
|
||||
qmltypesparser-test.cpp
|
||||
)
|
||||
|
||||
extend_qtc_test(unittest
|
||||
SOURCES_PREFIX "${QmlDesignerDir}/designercore"
|
||||
CONDITION TARGET qmldomlib
|
||||
DEPENDS qmldomlib
|
||||
SOURCES
|
||||
projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h
|
||||
projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h
|
||||
)
|
||||
|
@@ -582,12 +582,22 @@ const char *isQualifiedToString(IsQualified isQualified)
|
||||
const char *importKindToText(ImportKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case ImportKind::Module:
|
||||
return "Module";
|
||||
case ImportKind::Directory:
|
||||
return "Directory";
|
||||
case ImportKind::QmlTypesDependency:
|
||||
return "QmlTypesDependency";
|
||||
case ImportKind::Import:
|
||||
return "Import";
|
||||
case ImportKind::ModuleDependency:
|
||||
return "ModuleDependency";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *isAutoVersionToText(IsAutoVersion isAutoVersion)
|
||||
{
|
||||
switch (isAutoVersion) {
|
||||
case IsAutoVersion::No:
|
||||
return "is not autoversion";
|
||||
case IsAutoVersion::Yes:
|
||||
return "is auto version";
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -671,11 +681,6 @@ std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType)
|
||||
<< exportedType.version << ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const NativeType &nativeType)
|
||||
{
|
||||
return out << "(\"" << nativeType.name << "\")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const ImportedType &importedType)
|
||||
{
|
||||
return out << "(\"" << importedType.name << "\")";
|
||||
@@ -701,8 +706,8 @@ std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyD
|
||||
using Utils::operator<<;
|
||||
return out << "(\"" << propertyDeclaration.name << "\", " << propertyDeclaration.typeName
|
||||
<< ", " << propertyDeclaration.typeId << ", " << propertyDeclaration.traits << ", "
|
||||
<< propertyDeclaration.typeId << ", \"" << propertyDeclaration.aliasPropertyName
|
||||
<< "\")";
|
||||
<< propertyDeclaration.propertyTypeId << ", \""
|
||||
<< propertyDeclaration.aliasPropertyName << "\")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits)
|
||||
@@ -764,11 +769,22 @@ std::ostream &operator<<(std::ostream &out, const ImportKind &importKind)
|
||||
return out << importKindToText(importKind);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const IsAutoVersion &isAutoVersion)
|
||||
{
|
||||
return out << isAutoVersionToText(isAutoVersion);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const Import &import)
|
||||
{
|
||||
return out << "(" << import.moduleId << ", " << import.version << ", " << import.sourceId << ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const ModuleExportedImport &import)
|
||||
{
|
||||
return out << "(" << import.moduleId << ", " << import.exportedModuleId << ", "
|
||||
<< import.version << ", " << import.isAutoVersion << ")";
|
||||
}
|
||||
|
||||
} // namespace Storage
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -156,14 +156,12 @@ std::ostream &operator<<(std::ostream &out, const SourceContext &sourceContext);
|
||||
namespace Storage {
|
||||
class Type;
|
||||
class ExportedType;
|
||||
class NativeType;
|
||||
class ImportedType;
|
||||
class QualifiedImportedType;
|
||||
using TypeName = Utils::variant<NativeType, ExportedType>;
|
||||
class Version;
|
||||
class VersionNumber;
|
||||
enum class TypeAccessSemantics : int;
|
||||
enum class PropertyDeclarationTraits : unsigned int;
|
||||
enum class PropertyDeclarationTraits : int;
|
||||
class PropertyDeclaration;
|
||||
class FunctionDeclaration;
|
||||
class ParameterDeclaration;
|
||||
@@ -171,19 +169,20 @@ class SignalDeclaration;
|
||||
class EnumerationDeclaration;
|
||||
class EnumeratorDeclaration;
|
||||
enum class ImportKind : char;
|
||||
enum class IsAutoVersion : char;
|
||||
class Import;
|
||||
enum class IsQualified : int;
|
||||
class ProjectData;
|
||||
class SynchronizationPackage;
|
||||
enum class FileType : char;
|
||||
enum class ChangeLevel : char;
|
||||
class ModuleExportedImport;
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics);
|
||||
std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber);
|
||||
std::ostream &operator<<(std::ostream &out, Version version);
|
||||
std::ostream &operator<<(std::ostream &out, const Type &type);
|
||||
std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType);
|
||||
std::ostream &operator<<(std::ostream &out, const NativeType &nativeType);
|
||||
std::ostream &operator<<(std::ostream &out, const ImportedType &importedType);
|
||||
std::ostream &operator<<(std::ostream &out, const QualifiedImportedType &importedType);
|
||||
std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyDeclaration);
|
||||
@@ -200,6 +199,7 @@ std::ostream &operator<<(std::ostream &out, const ProjectData &data);
|
||||
std::ostream &operator<<(std::ostream &out, const SynchronizationPackage &package);
|
||||
std::ostream &operator<<(std::ostream &out, FileType fileType);
|
||||
std::ostream &operator<<(std::ostream &out, ChangeLevel changeLevel);
|
||||
std::ostream &operator<<(std::ostream &out, const ModuleExportedImport &import);
|
||||
|
||||
} // namespace Storage
|
||||
|
||||
|
@@ -1,36 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include <projectstorage/projectmanagerinterface.h>
|
||||
|
||||
class ProjectManagerMock : public QmlDesigner::ProjectManagerInterface
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD(QStringList, qtQmlDirs, (), (const));
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,6 @@
|
||||
#include "googletest.h"
|
||||
|
||||
#include "filesystemmock.h"
|
||||
#include "projectmanagermock.h"
|
||||
#include "projectstoragemock.h"
|
||||
#include "qmldocumentparsermock.h"
|
||||
#include "qmltypesparsermock.h"
|
||||
@@ -48,6 +47,10 @@ using QmlDesigner::Storage::TypeAccessSemantics;
|
||||
namespace Storage = QmlDesigner::Storage;
|
||||
using QmlDesigner::IdPaths;
|
||||
using QmlDesigner::Storage::FileType;
|
||||
using QmlDesigner::Storage::Import;
|
||||
using QmlDesigner::Storage::IsAutoVersion;
|
||||
using QmlDesigner::Storage::ModuleExportedImport;
|
||||
using QmlDesigner::Storage::ProjectData;
|
||||
using QmlDesigner::Storage::SynchronizationPackage;
|
||||
using QmlDesigner::Storage::Version;
|
||||
|
||||
@@ -120,7 +123,7 @@ MATCHER_P4(IsProjectData,
|
||||
{
|
||||
const Storage::ProjectData &projectData = arg;
|
||||
|
||||
return projectData.projectSourceId == projectSourceId && projectData.sourceId == sourceId
|
||||
return &projectData.projectSourceId == &projectSourceId && projectData.sourceId == sourceId
|
||||
&& projectData.moduleId == moduleId && projectData.fileType == fileType;
|
||||
}
|
||||
|
||||
@@ -130,7 +133,9 @@ MATCHER(PackageIsEmpty, std::string(negation ? "isn't empty" : "is empty"))
|
||||
|
||||
return package.imports.empty() && package.types.empty() && package.fileStatuses.empty()
|
||||
&& package.updatedSourceIds.empty() && package.projectDatas.empty()
|
||||
&& package.updatedFileStatusSourceIds.empty() && package.updatedProjectSourceIds.empty();
|
||||
&& package.updatedFileStatusSourceIds.empty() && package.updatedProjectSourceIds.empty()
|
||||
&& package.moduleDependencies.empty() && package.updatedModuleDependencySourceIds.empty()
|
||||
&& package.moduleExportedImports.empty() && package.updatedModuleIds.empty();
|
||||
}
|
||||
|
||||
class ProjectStorageUpdater : public testing::Test
|
||||
@@ -153,7 +158,6 @@ public:
|
||||
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
|
||||
.WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421}));
|
||||
|
||||
ON_CALL(projectManagerMock, qtQmlDirs()).WillByDefault(Return(QStringList{"/path/qmldir"}));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
|
||||
.WillByDefault(Return(qmldirContent));
|
||||
|
||||
@@ -169,8 +173,9 @@ public:
|
||||
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
|
||||
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
|
||||
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 2}));
|
||||
ON_CALL(projectStorageMock, moduleId(Eq("Example"))).WillByDefault(Return(exampleModuleId));
|
||||
ON_CALL(projectStorageMock, moduleId(Eq("Qml"))).WillByDefault(Return(qmlModuleId));
|
||||
ON_CALL(projectStorageMock, moduleId(_)).WillByDefault([&](const auto &name) {
|
||||
return storage.moduleId(name);
|
||||
});
|
||||
|
||||
firstType.prototype = Storage::ImportedType{"Object"};
|
||||
secondType.prototype = Storage::ImportedType{"Object2"};
|
||||
@@ -178,27 +183,30 @@ public:
|
||||
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
|
||||
.WillByDefault(Return(qmlDocument1));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.2.qml"))))
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First2.qml"))))
|
||||
.WillByDefault(Return(qmlDocument2));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
|
||||
.WillByDefault(Return(qmlDocument3));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
|
||||
.WillByDefault(Return(qmltypes1));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example2.qmltypes"))))
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/types/example2.qmltypes"))))
|
||||
.WillByDefault(Return(qmltypes2));
|
||||
|
||||
ON_CALL(qmlDocumentParserMock, parse(qmlDocument1, _)).WillByDefault([&](auto, auto &imports) {
|
||||
imports.push_back(import1);
|
||||
return firstType;
|
||||
});
|
||||
ON_CALL(qmlDocumentParserMock, parse(qmlDocument2, _)).WillByDefault([&](auto, auto &imports) {
|
||||
imports.push_back(import2);
|
||||
return secondType;
|
||||
});
|
||||
ON_CALL(qmlDocumentParserMock, parse(qmlDocument3, _)).WillByDefault([&](auto, auto &imports) {
|
||||
imports.push_back(import3);
|
||||
return thirdType;
|
||||
});
|
||||
ON_CALL(qmlDocumentParserMock, parse(qmlDocument1, _, _, _))
|
||||
.WillByDefault([&](auto, auto &imports, auto, auto) {
|
||||
imports.push_back(import1);
|
||||
return firstType;
|
||||
});
|
||||
ON_CALL(qmlDocumentParserMock, parse(qmlDocument2, _, _, _))
|
||||
.WillByDefault([&](auto, auto &imports, auto, auto) {
|
||||
imports.push_back(import2);
|
||||
return secondType;
|
||||
});
|
||||
ON_CALL(qmlDocumentParserMock, parse(qmlDocument3, _, _, _))
|
||||
.WillByDefault([&](auto, auto &imports, auto, auto) {
|
||||
imports.push_back(import3);
|
||||
return thirdType;
|
||||
});
|
||||
ON_CALL(qmlTypesParserMock, parse(Eq(qmltypes1), _, _, _))
|
||||
.WillByDefault([&](auto, auto &imports, auto &types, auto) {
|
||||
types.push_back(objectType);
|
||||
@@ -212,7 +220,6 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
NiceMock<ProjectManagerMock> projectManagerMock;
|
||||
NiceMock<FileSystemMock> fileSystemMock;
|
||||
NiceMock<ProjectStorageMock> projectStorageMock;
|
||||
NiceMock<QmlTypesParserMock> qmlTypesParserMock;
|
||||
@@ -222,29 +229,36 @@ protected:
|
||||
QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
|
||||
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
|
||||
storage};
|
||||
QmlDesigner::ProjectUpdater updater{projectManagerMock,
|
||||
fileSystemMock,
|
||||
projectStorageMock,
|
||||
fileStatusCache,
|
||||
sourcePathCache,
|
||||
qmlDocumentParserMock,
|
||||
qmlTypesParserMock};
|
||||
QmlDesigner::ProjectStorageUpdater updater{fileSystemMock,
|
||||
projectStorageMock,
|
||||
fileStatusCache,
|
||||
sourcePathCache,
|
||||
qmlDocumentParserMock,
|
||||
qmlTypesParserMock};
|
||||
SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes");
|
||||
SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/example2.qmltypes");
|
||||
SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/types/example2.qmltypes");
|
||||
SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
|
||||
SourceId qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml");
|
||||
SourceId qmlDocumentSourceId2 = sourcePathCache.sourceId("/path/First.2.qml");
|
||||
SourceId qmlDocumentSourceId2 = sourcePathCache.sourceId("/path/First2.qml");
|
||||
SourceId qmlDocumentSourceId3 = sourcePathCache.sourceId("/path/Second.qml");
|
||||
ModuleId qmlModuleId{storage.moduleId("Qml")};
|
||||
ModuleId qmlCppNativeModuleId{storage.moduleId("Qml-cppnative")};
|
||||
ModuleId exampleModuleId{storage.moduleId("Example")};
|
||||
ModuleId exampleCppNativeModuleId{storage.moduleId("Example-cppnative")};
|
||||
ModuleId builtinModuleId{storage.moduleId("QML")};
|
||||
ModuleId builtinCppNativeModuleId{storage.moduleId("QML-cppnative")};
|
||||
ModuleId quickModuleId{storage.moduleId("Quick")};
|
||||
ModuleId quickCppNativeModuleId{storage.moduleId("Quick-cppnative")};
|
||||
ModuleId pathModuleId{storage.moduleId("/path")};
|
||||
ModuleId subPathQmlModuleId{storage.moduleId("/path/qml")};
|
||||
Storage::Type objectType{"QObject",
|
||||
Storage::NativeType{},
|
||||
Storage::ImportedType{},
|
||||
Storage::TypeAccessSemantics::Reference,
|
||||
qmltypesPathSourceId,
|
||||
{Storage::ExportedType{exampleModuleId, "Object"},
|
||||
Storage::ExportedType{exampleModuleId, "Obj"}}};
|
||||
Storage::Type itemType{"QItem",
|
||||
Storage::NativeType{},
|
||||
Storage::ImportedType{},
|
||||
Storage::TypeAccessSemantics::Reference,
|
||||
qmltypes2PathSourceId,
|
||||
{Storage::ExportedType{exampleModuleId, "Item"}}};
|
||||
@@ -262,6 +276,7 @@ protected:
|
||||
QString qmldirContent{"module Example\ntypeinfo example.qmltypes\n"};
|
||||
QString qmltypes1{"Module {\ndependencies: [module1]}"};
|
||||
QString qmltypes2{"Module {\ndependencies: [module2]}"};
|
||||
QStringList qmlDirs = {"/path/qmldir"};
|
||||
};
|
||||
|
||||
TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
|
||||
@@ -269,9 +284,7 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
|
||||
SourceId qmlDir1PathSourceId = sourcePathCache.sourceId("/path/one/qmldir");
|
||||
SourceId qmlDir2PathSourceId = sourcePathCache.sourceId("/path/two/qmldir");
|
||||
SourceId qmlDir3PathSourceId = sourcePathCache.sourceId("/path/three/qmldir");
|
||||
ON_CALL(projectManagerMock, qtQmlDirs())
|
||||
.WillByDefault(
|
||||
Return(QStringList{"/path/one/qmldir", "/path/two/qmldir", "/path/three/qmldir"}));
|
||||
QStringList qmlDirs = {"/path/one/qmldir", "/path/two/qmldir", "/path/three/qmldir"};
|
||||
ON_CALL(fileSystemMock, fileStatus(_)).WillByDefault([](auto sourceId) {
|
||||
return FileStatus{sourceId, 21, 421};
|
||||
});
|
||||
@@ -286,7 +299,7 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/one/qmldir"))));
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/two/qmldir"))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, RequestFileStatusFromFileSystem)
|
||||
@@ -295,7 +308,7 @@ TEST_F(ProjectStorageUpdater, RequestFileStatusFromFileSystem)
|
||||
|
||||
EXPECT_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, GetContentForQmlTypes)
|
||||
@@ -307,7 +320,7 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypes)
|
||||
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsInvalid)
|
||||
@@ -321,7 +334,7 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsI
|
||||
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsInvalid)
|
||||
@@ -334,26 +347,28 @@ TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsI
|
||||
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))).Times(0);
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, ParseQmlTypes)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
typeinfo example.qmltypes
|
||||
typeinfo example2.qmltypes)"};
|
||||
typeinfo types/example2.qmltypes)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
QString qmltypes{"Module {\ndependencies: []}"};
|
||||
QString qmltypes2{"Module {\ndependencies: [foo]}"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
|
||||
.WillByDefault(Return(qmltypes));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example2.qmltypes"))))
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/types/example2.qmltypes"))))
|
||||
.WillByDefault(Return(qmltypes2));
|
||||
|
||||
EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _));
|
||||
EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _));
|
||||
EXPECT_CALL(qmlTypesParserMock,
|
||||
parse(qmltypes, _, _, Field(&ProjectData::moduleId, exampleCppNativeModuleId)));
|
||||
EXPECT_CALL(qmlTypesParserMock,
|
||||
parse(qmltypes2, _, _, Field(&ProjectData::moduleId, exampleCppNativeModuleId)));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
|
||||
@@ -367,7 +382,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
|
||||
|
||||
EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
|
||||
@@ -383,6 +398,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
|
||||
});
|
||||
|
||||
EXPECT_CALL(projectStorageMock, moduleId(Eq("Example")));
|
||||
EXPECT_CALL(projectStorageMock, moduleId(Eq("Example-cppnative")));
|
||||
EXPECT_CALL(projectStorageMock, moduleId(Eq("/path")));
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::imports, ElementsAre(import)),
|
||||
@@ -395,12 +412,12 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
|
||||
Field(&SynchronizationPackage::projectDatas,
|
||||
UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
|
||||
qmltypesPathSourceId,
|
||||
exampleModuleId,
|
||||
exampleCppNativeModuleId,
|
||||
FileType::QmlTypes))),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId)))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
|
||||
@@ -419,28 +436,37 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
|
||||
|
||||
EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, GetContentForQmlDocuments)
|
||||
{
|
||||
QString qmldir{"module Example\nFirstType 1.0 First.qml\nFirstTypeV2 2.2 "
|
||||
"First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"};
|
||||
SourceId oldSecondSourceId3 = sourcePathCache.sourceId("/path/OldSecond.qml");
|
||||
ON_CALL(fileSystemMock, fileStatus(Eq(oldSecondSourceId3)))
|
||||
.WillByDefault(Return(FileStatus{oldSecondSourceId3, 22, 14}));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/OldSecond.qml"))))
|
||||
.WillByDefault(Return(qmlDocument3));
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstTypeV2 2.2 First2.qml
|
||||
SecondType 2.1 OldSecond.qml
|
||||
SecondType 2.2 Second.qml)"};
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
|
||||
.WillRepeatedly(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))));
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.2.qml"))));
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First2.qml"))));
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/OldSecond.qml"))));
|
||||
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, ParseQmlDocuments)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstTypeV2 2.2 First.2.qml
|
||||
FirstTypeV2 2.2 First2.qml
|
||||
SecondType 2.2 Second.qml)"};
|
||||
QString qmlDocument1{"First{}"};
|
||||
QString qmlDocument2{"Second{}"};
|
||||
@@ -448,16 +474,16 @@ TEST_F(ProjectStorageUpdater, ParseQmlDocuments)
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
|
||||
.WillByDefault(Return(qmlDocument1));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.2.qml"))))
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First2.qml"))))
|
||||
.WillByDefault(Return(qmlDocument2));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
|
||||
.WillByDefault(Return(qmlDocument3));
|
||||
|
||||
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument1, _));
|
||||
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument2, _));
|
||||
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument3, _));
|
||||
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument1, _, _, _));
|
||||
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument2, _, _, _));
|
||||
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument3, _, _, _));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, ParseQmlDocumentsWithNonExistingQmlDocumentThrows)
|
||||
@@ -466,14 +492,14 @@ TEST_F(ProjectStorageUpdater, ParseQmlDocumentsWithNonExistingQmlDocumentThrows)
|
||||
NonexitingType 1.0 NonexitingType.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
ASSERT_THROW(updater.update(), QmlDesigner::CannotParseQmlDocumentFile);
|
||||
ASSERT_THROW(updater.update(qmlDirs, {}), QmlDesigner::CannotParseQmlDocumentFile);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstType 2.2 First.2.qml
|
||||
FirstType 2.2 First2.qml
|
||||
SecondType 2.2 Second.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
@@ -489,21 +515,24 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
|
||||
qmlDocumentSourceId1,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))),
|
||||
AllOf(IsStorageType("First.2.qml",
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
|
||||
IsExportedType(pathModuleId, "First", -1, -1)))),
|
||||
AllOf(IsStorageType("First2.qml",
|
||||
Storage::ImportedType{"Object2"},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId2,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))),
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
|
||||
IsExportedType(pathModuleId, "First2", -1, -1)))),
|
||||
AllOf(IsStorageType("Second.qml",
|
||||
Storage::ImportedType{"Object3"},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId3,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2)))))),
|
||||
ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
|
||||
IsExportedType(pathModuleId, "Second", -1, -1)))))),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId,
|
||||
qmlDocumentSourceId1,
|
||||
@@ -535,16 +564,16 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
|
||||
exampleModuleId,
|
||||
FileType::QmlDocument))))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeRemoved)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstType 2.2 First.2.qml
|
||||
FirstType 2.2 First2.qml
|
||||
typeinfo example.qmltypes
|
||||
typeinfo example2.qmltypes
|
||||
typeinfo types/example2.qmltypes
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2)))
|
||||
@@ -572,14 +601,16 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemoved)
|
||||
qmlDocumentSourceId1,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))),
|
||||
AllOf(IsStorageType("First.2.qml",
|
||||
Storage::NativeType{},
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
|
||||
IsExportedType(pathModuleId, "First", -1, -1)))),
|
||||
AllOf(IsStorageType("First2.qml",
|
||||
Storage::ImportedType{},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId2,
|
||||
Storage::ChangeLevel::Minimal),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))))),
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
|
||||
IsExportedType(pathModuleId, "First2", -1, -1)))))),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId,
|
||||
qmltypesPathSourceId,
|
||||
@@ -608,21 +639,21 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemoved)
|
||||
FileType::QmlDocument),
|
||||
IsProjectData(qmlDirPathSourceId,
|
||||
qmltypesPathSourceId,
|
||||
exampleModuleId,
|
||||
exampleCppNativeModuleId,
|
||||
FileType::QmlTypes),
|
||||
IsProjectData(qmlDirPathSourceId,
|
||||
qmltypes2PathSourceId,
|
||||
exampleModuleId,
|
||||
exampleCppNativeModuleId,
|
||||
FileType::QmlTypes))))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstType 2.2 First.2.qml
|
||||
FirstType 2.2 First2.qml
|
||||
SecondType 2.2 Second.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
|
||||
@@ -640,21 +671,24 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
|
||||
qmlDocumentSourceId1,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))),
|
||||
AllOf(IsStorageType("First.2.qml",
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
|
||||
IsExportedType(pathModuleId, "First", -1, -1)))),
|
||||
AllOf(IsStorageType("First2.qml",
|
||||
Storage::ImportedType{"Object2"},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId2,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))),
|
||||
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
|
||||
IsExportedType(pathModuleId, "First2", -1, -1)))),
|
||||
AllOf(IsStorageType("Second.qml",
|
||||
Storage::NativeType{},
|
||||
Storage::ImportedType{},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId3,
|
||||
Storage::ChangeLevel::Minimal),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2)))))),
|
||||
ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
|
||||
IsExportedType(pathModuleId, "Second", -1, -1)))))),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId,
|
||||
qmlDocumentSourceId1,
|
||||
@@ -682,14 +716,14 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
|
||||
exampleModuleId,
|
||||
FileType::QmlDocument))))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.1 First.qml
|
||||
FirstType 2.2 First.2.qml
|
||||
FirstType 2.2 First2.qml
|
||||
SecondType 2.2 Second.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
|
||||
@@ -716,7 +750,7 @@ TEST_F(ProjectStorageUpdater, AddSourceIdForForInvalidQmldirFileStatus)
|
||||
Field(&SynchronizationPackage::fileStatuses, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds, IsEmpty()),
|
||||
Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
|
||||
@@ -744,7 +778,7 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
|
||||
qmlDocumentSourceId1,
|
||||
Storage::ChangeLevel::ExcludeExportedTypes),
|
||||
Field(&Storage::Type::exportedTypes, IsEmpty())),
|
||||
AllOf(IsStorageType("First.2.qml",
|
||||
AllOf(IsStorageType("First2.qml",
|
||||
Storage::ImportedType{"Object2"},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId2,
|
||||
@@ -767,7 +801,7 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
|
||||
qmlDocumentSourceId2)),
|
||||
Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedFiles)
|
||||
@@ -806,7 +840,464 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedF
|
||||
UnorderedElementsAre(qmltypesPathSourceId, qmlDocumentSourceId1)),
|
||||
Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
|
||||
|
||||
updater.update();
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, UpdateQmlTypesFilesIsEmpty)
|
||||
{
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::imports, IsEmpty()),
|
||||
Field(&SynchronizationPackage::types, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedSourceIds, IsEmpty()),
|
||||
Field(&SynchronizationPackage::fileStatuses, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds, IsEmpty()),
|
||||
Field(&SynchronizationPackage::projectDatas, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds, IsEmpty()))));
|
||||
|
||||
updater.update({}, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, UpdateQmlTypesFiles)
|
||||
{
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(AllOf(
|
||||
Field(&SynchronizationPackage::imports, UnorderedElementsAre(import4, import5)),
|
||||
Field(&SynchronizationPackage::types, UnorderedElementsAre(objectType, itemType)),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)),
|
||||
Field(&SynchronizationPackage::fileStatuses,
|
||||
UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421),
|
||||
IsFileStatus(qmltypes2PathSourceId, 21, 421))),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)),
|
||||
Field(&SynchronizationPackage::projectDatas,
|
||||
UnorderedElementsAre(IsProjectData(qmltypesPathSourceId,
|
||||
qmltypesPathSourceId,
|
||||
builtinCppNativeModuleId,
|
||||
FileType::QmlTypes),
|
||||
IsProjectData(qmltypes2PathSourceId,
|
||||
qmltypes2PathSourceId,
|
||||
builtinCppNativeModuleId,
|
||||
FileType::QmlTypes))),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds, IsEmpty()))));
|
||||
|
||||
updater.update({}, {"/path/example.qmltypes", "/path/types/example2.qmltypes"});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, DontUpdateQmlTypesFilesIfUnchanged)
|
||||
{
|
||||
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
|
||||
.WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import4)),
|
||||
Field(&SynchronizationPackage::types, UnorderedElementsAre(objectType)),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId)),
|
||||
Field(&SynchronizationPackage::fileStatuses,
|
||||
UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421))),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId)),
|
||||
Field(&SynchronizationPackage::projectDatas,
|
||||
UnorderedElementsAre(IsProjectData(qmltypesPathSourceId,
|
||||
qmltypesPathSourceId,
|
||||
builtinCppNativeModuleId,
|
||||
FileType::QmlTypes))),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds, IsEmpty()))));
|
||||
|
||||
updater.update({}, {"/path/example.qmltypes", "/path/types/example2.qmltypes"});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithDifferentVersionButSameTypeNameAndFileName)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstType 1.1 First.qml
|
||||
FirstType 6.0 First.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
|
||||
Field(&SynchronizationPackage::types,
|
||||
UnorderedElementsAre(AllOf(
|
||||
IsStorageType("First.qml",
|
||||
Storage::ImportedType{"Object"},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId1,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(
|
||||
IsExportedType(exampleModuleId, "FirstType", 1, 0),
|
||||
IsExportedType(exampleModuleId, "FirstType", 1, 1),
|
||||
IsExportedType(exampleModuleId, "FirstType", 6, 0),
|
||||
IsExportedType(pathModuleId, "First", -1, -1)))))),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
|
||||
Field(&SynchronizationPackage::fileStatuses,
|
||||
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
|
||||
IsFileStatus(qmlDocumentSourceId1, 22, 12))),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId)),
|
||||
Field(&SynchronizationPackage::projectDatas,
|
||||
UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
|
||||
qmlDocumentSourceId1,
|
||||
exampleModuleId,
|
||||
FileType::QmlDocument))))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithDifferentTypeNameButSameVersionAndFileName)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstType2 1.0 First.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
|
||||
Field(&SynchronizationPackage::types,
|
||||
UnorderedElementsAre(
|
||||
AllOf(IsStorageType("First.qml",
|
||||
Storage::ImportedType{"Object"},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId1,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(
|
||||
IsExportedType(exampleModuleId, "FirstType", 1, 0),
|
||||
IsExportedType(exampleModuleId, "FirstType2", 1, 0),
|
||||
IsExportedType(pathModuleId, "First", -1, -1)))))),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
|
||||
Field(&SynchronizationPackage::fileStatuses,
|
||||
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
|
||||
IsFileStatus(qmlDocumentSourceId1, 22, 12))),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId)),
|
||||
Field(&SynchronizationPackage::projectDatas,
|
||||
UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
|
||||
qmlDocumentSourceId1,
|
||||
exampleModuleId,
|
||||
FileType::QmlDocument))))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, DontSynchronizeSelectors)
|
||||
{
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/+First.qml"))))
|
||||
.WillByDefault(Return(qmlDocument1));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qml/+First.qml"))))
|
||||
.WillByDefault(Return(qmlDocument1));
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 +First.qml
|
||||
FirstType2 1.0 qml/+First.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::imports, IsEmpty()),
|
||||
Field(&SynchronizationPackage::types, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId)),
|
||||
Field(&SynchronizationPackage::fileStatuses,
|
||||
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421))),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId)),
|
||||
Field(&SynchronizationPackage::projectDatas, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithRelativeFilePath)
|
||||
{
|
||||
SourceId qmlDocumentSourceId = sourcePathCache.sourceId("/path/First.qml");
|
||||
ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId)))
|
||||
.WillByDefault(Return(FileStatus{qmlDocumentSourceId, 22, 12}));
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
|
||||
.WillByDefault(Return(qmlDocument1));
|
||||
QString qmldir{R"(module Example
|
||||
FirstType 1.0 First.qml
|
||||
FirstType2 1.0 First.qml)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
|
||||
Field(&SynchronizationPackage::types,
|
||||
UnorderedElementsAre(
|
||||
AllOf(IsStorageType("First.qml",
|
||||
Storage::ImportedType{"Object"},
|
||||
TypeAccessSemantics::Reference,
|
||||
qmlDocumentSourceId,
|
||||
Storage::ChangeLevel::Full),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(
|
||||
IsExportedType(exampleModuleId, "FirstType", 1, 0),
|
||||
IsExportedType(exampleModuleId, "FirstType2", 1, 0),
|
||||
IsExportedType(pathModuleId, "First", -1, -1)))))),
|
||||
Field(&SynchronizationPackage::updatedSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId)),
|
||||
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId)),
|
||||
Field(&SynchronizationPackage::fileStatuses,
|
||||
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
|
||||
IsFileStatus(qmlDocumentSourceId, 22, 12))),
|
||||
Field(&SynchronizationPackage::updatedProjectSourceIds,
|
||||
UnorderedElementsAre(qmlDirPathSourceId)),
|
||||
Field(&SynchronizationPackage::projectDatas,
|
||||
UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
|
||||
qmlDocumentSourceId,
|
||||
exampleModuleId,
|
||||
FileType::QmlDocument))))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependencies)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
depends Qml
|
||||
depends QML
|
||||
typeinfo example.qmltypes
|
||||
typeinfo types/example2.qmltypes
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(
|
||||
projectStorageMock,
|
||||
synchronize(AllOf(
|
||||
Field(&SynchronizationPackage::moduleDependencies,
|
||||
UnorderedElementsAre(
|
||||
Import{qmlCppNativeModuleId, Storage::Version{}, qmltypesPathSourceId},
|
||||
Import{builtinCppNativeModuleId, Storage::Version{}, qmltypesPathSourceId},
|
||||
Import{qmlCppNativeModuleId, Storage::Version{}, qmltypes2PathSourceId},
|
||||
Import{builtinCppNativeModuleId, Storage::Version{}, qmltypes2PathSourceId})),
|
||||
Field(&SynchronizationPackage::updatedModuleDependencySourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithDoubleEntries)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
depends Qml
|
||||
depends QML
|
||||
depends Qml
|
||||
typeinfo example.qmltypes
|
||||
typeinfo types/example2.qmltypes
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(
|
||||
projectStorageMock,
|
||||
synchronize(AllOf(
|
||||
Field(&SynchronizationPackage::moduleDependencies,
|
||||
UnorderedElementsAre(
|
||||
Import{qmlCppNativeModuleId, Storage::Version{}, qmltypesPathSourceId},
|
||||
Import{builtinCppNativeModuleId, Storage::Version{}, qmltypesPathSourceId},
|
||||
Import{qmlCppNativeModuleId, Storage::Version{}, qmltypes2PathSourceId},
|
||||
Import{builtinCppNativeModuleId, Storage::Version{}, qmltypes2PathSourceId})),
|
||||
Field(&SynchronizationPackage::updatedModuleDependencySourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithCollidingImports)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
depends Qml
|
||||
depends QML
|
||||
import Qml
|
||||
typeinfo example.qmltypes
|
||||
typeinfo types/example2.qmltypes
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(
|
||||
projectStorageMock,
|
||||
synchronize(AllOf(
|
||||
Field(&SynchronizationPackage::moduleDependencies,
|
||||
UnorderedElementsAre(
|
||||
Import{qmlCppNativeModuleId, Storage::Version{}, qmltypesPathSourceId},
|
||||
Import{builtinCppNativeModuleId, Storage::Version{}, qmltypesPathSourceId},
|
||||
Import{qmlCppNativeModuleId, Storage::Version{}, qmltypes2PathSourceId},
|
||||
Import{builtinCppNativeModuleId, Storage::Version{}, qmltypes2PathSourceId})),
|
||||
Field(&SynchronizationPackage::updatedModuleDependencySourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirWithNoDependencies)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
typeinfo example.qmltypes
|
||||
typeinfo types/example2.qmltypes
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::moduleDependencies, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedModuleDependencySourceIds,
|
||||
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirImports)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
import Qml auto
|
||||
import QML 2.1
|
||||
import Quick
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::moduleExportedImports,
|
||||
UnorderedElementsAre(ModuleExportedImport{exampleModuleId,
|
||||
qmlModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::Yes},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
qmlCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleModuleId,
|
||||
builtinModuleId,
|
||||
Storage::Version{2, 1},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
builtinCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleModuleId,
|
||||
quickModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
quickCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No})),
|
||||
Field(&SynchronizationPackage::updatedModuleIds,
|
||||
ElementsAre(exampleModuleId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirWithNoImports)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(AllOf(Field(&SynchronizationPackage::moduleExportedImports, IsEmpty()),
|
||||
Field(&SynchronizationPackage::updatedModuleIds,
|
||||
ElementsAre(exampleModuleId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirImportsWithDoubleEntries)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
import Qml auto
|
||||
import QML 2.1
|
||||
import Quick
|
||||
import Qml
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::moduleExportedImports,
|
||||
UnorderedElementsAre(ModuleExportedImport{exampleModuleId,
|
||||
qmlModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::Yes},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
qmlCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleModuleId,
|
||||
builtinModuleId,
|
||||
Storage::Version{2, 1},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
builtinCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleModuleId,
|
||||
quickModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
quickCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No})),
|
||||
Field(&SynchronizationPackage::updatedModuleIds,
|
||||
ElementsAre(exampleModuleId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorageUpdater, SynchronizeQmldirOptionalImports)
|
||||
{
|
||||
QString qmldir{R"(module Example
|
||||
import Qml auto
|
||||
import QML 2.1
|
||||
optional import Quick
|
||||
)"};
|
||||
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
|
||||
|
||||
EXPECT_CALL(projectStorageMock,
|
||||
synchronize(
|
||||
AllOf(Field(&SynchronizationPackage::moduleExportedImports,
|
||||
UnorderedElementsAre(ModuleExportedImport{exampleModuleId,
|
||||
qmlModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::Yes},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
qmlCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleModuleId,
|
||||
builtinModuleId,
|
||||
Storage::Version{2, 1},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
builtinCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleModuleId,
|
||||
quickModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No},
|
||||
ModuleExportedImport{exampleCppNativeModuleId,
|
||||
quickCppNativeModuleId,
|
||||
Storage::Version{},
|
||||
IsAutoVersion::No})),
|
||||
Field(&SynchronizationPackage::updatedModuleIds,
|
||||
ElementsAre(exampleModuleId)))));
|
||||
|
||||
updater.update(qmlDirs, {});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@@ -59,6 +59,41 @@ MATCHER_P3(IsPropertyDeclaration,
|
||||
&& propertyDeclaration.traits == traits;
|
||||
}
|
||||
|
||||
MATCHER_P4(IsAliasPropertyDeclaration,
|
||||
name,
|
||||
typeName,
|
||||
traits,
|
||||
aliasPropertyName,
|
||||
std::string(negation ? "isn't " : "is ")
|
||||
+ PrintToString(Storage::PropertyDeclaration{name, typeName, traits, aliasPropertyName}))
|
||||
{
|
||||
const Storage::PropertyDeclaration &propertyDeclaration = arg;
|
||||
|
||||
return propertyDeclaration.name == name
|
||||
&& Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName
|
||||
&& propertyDeclaration.traits == traits
|
||||
&& propertyDeclaration.aliasPropertyName == aliasPropertyName
|
||||
&& propertyDeclaration.aliasPropertyNameTail.empty();
|
||||
}
|
||||
|
||||
MATCHER_P5(IsAliasPropertyDeclaration,
|
||||
name,
|
||||
typeName,
|
||||
traits,
|
||||
aliasPropertyName,
|
||||
aliasPropertyNameTail,
|
||||
std::string(negation ? "isn't " : "is ")
|
||||
+ PrintToString(Storage::PropertyDeclaration{name, typeName, traits, aliasPropertyName}))
|
||||
{
|
||||
const Storage::PropertyDeclaration &propertyDeclaration = arg;
|
||||
|
||||
return propertyDeclaration.name == name
|
||||
&& Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName
|
||||
&& propertyDeclaration.traits == traits
|
||||
&& propertyDeclaration.aliasPropertyName == aliasPropertyName
|
||||
&& propertyDeclaration.aliasPropertyNameTail == aliasPropertyNameTail;
|
||||
}
|
||||
|
||||
MATCHER_P2(IsFunctionDeclaration,
|
||||
name,
|
||||
returnTypeName,
|
||||
@@ -129,12 +164,12 @@ protected:
|
||||
QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
|
||||
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
|
||||
storage};
|
||||
QmlDesigner::QmlDocumentParser parser{storage};
|
||||
QmlDesigner::QmlDocumentParser parser{storage, sourcePathCache};
|
||||
Storage::Imports imports;
|
||||
SourceId qmlFileSourceId{sourcePathCache.sourceId("path/to/qmlfile.qml")};
|
||||
SourceId qmlFileSourceId{sourcePathCache.sourceId("/path/to/qmlfile.qml")};
|
||||
SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)};
|
||||
QString directoryPath{"/path/to"};
|
||||
ModuleId directoryModuleId{storage.moduleId("/path/to")};
|
||||
Utils::PathString directoryPath{sourcePathCache.sourceContextPath(qmlFileSourceContextId)};
|
||||
ModuleId directoryModuleId{storage.moduleId(directoryPath)};
|
||||
};
|
||||
|
||||
TEST_F(QmlDocumentParser, Prototype)
|
||||
@@ -144,22 +179,24 @@ TEST_F(QmlDocumentParser, Prototype)
|
||||
ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example")));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype)
|
||||
TEST_F(QmlDocumentParser, QualifiedPrototype)
|
||||
{
|
||||
auto exampleModuleId = storage.moduleId("Example");
|
||||
auto type = parser.parse("import Example as Example\n Example.Item{}",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
QString text = R"(import Example 2.1 as Example
|
||||
Example.Item{})";
|
||||
|
||||
auto type = parser.parse(text, imports, qmlFileSourceId, directoryPath);
|
||||
|
||||
ASSERT_THAT(type,
|
||||
HasPrototype(Storage::QualifiedImportedType(
|
||||
"Item", Storage::Import{exampleModuleId, Storage::Version{}, qmlFileSourceId})));
|
||||
HasPrototype(Storage::QualifiedImportedType("Item",
|
||||
Storage::Import{exampleModuleId,
|
||||
Storage::Version{2, 1},
|
||||
qmlFileSourceId})));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, Properties)
|
||||
{
|
||||
auto type = parser.parse("Example{\n property int foo\n}", imports, qmlFileSourceId, directoryPath);
|
||||
auto type = parser.parse(R"(Example{ property int foo })", imports, qmlFileSourceId, directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsPropertyDeclaration("foo",
|
||||
@@ -167,12 +204,66 @@ TEST_F(QmlDocumentParser, Properties)
|
||||
Storage::PropertyDeclarationTraits::None)));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, QualifiedProperties)
|
||||
{
|
||||
auto exampleModuleId = storage.moduleId("Example");
|
||||
|
||||
auto type = parser.parse(R"(import Example 2.1 as Example
|
||||
Item{ property Example.Foo foo})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsPropertyDeclaration(
|
||||
"foo",
|
||||
Storage::QualifiedImportedType("Foo",
|
||||
Storage::Import{exampleModuleId,
|
||||
Storage::Version{2, 1},
|
||||
qmlFileSourceId}),
|
||||
Storage::PropertyDeclarationTraits::None)));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, EnumerationInProperties)
|
||||
{
|
||||
auto type = parser.parse(R"(import Example 2.1 as Example
|
||||
Item{ property Enumeration.Foo foo})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsPropertyDeclaration("foo",
|
||||
Storage::ImportedType("Enumeration.Foo"),
|
||||
Storage::PropertyDeclarationTraits::None)));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, QualifiedEnumerationInProperties)
|
||||
{
|
||||
auto exampleModuleId = storage.moduleId("Example");
|
||||
|
||||
auto type = parser.parse(R"(import Example 2.1 as Example
|
||||
Item{ property Example.Enumeration.Foo foo})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsPropertyDeclaration(
|
||||
"foo",
|
||||
Storage::QualifiedImportedType("Enumeration.Foo",
|
||||
Storage::Import{exampleModuleId,
|
||||
Storage::Version{2, 1},
|
||||
qmlFileSourceId}),
|
||||
Storage::PropertyDeclarationTraits::None)));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, Imports)
|
||||
{
|
||||
ModuleId fooDirectoryModuleId = storage.moduleId("/path/foo");
|
||||
ModuleId qmlModuleId = storage.moduleId("QML");
|
||||
ModuleId qtQmlModuleId = storage.moduleId("QtQml");
|
||||
ModuleId qtQuickModuleId = storage.moduleId("QtQuick");
|
||||
|
||||
auto type = parser.parse(R"(import QtQuick
|
||||
import "../foo"
|
||||
Example{})",
|
||||
@@ -184,11 +275,51 @@ TEST_F(QmlDocumentParser, Imports)
|
||||
UnorderedElementsAre(
|
||||
Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{qmlModuleId, Storage::Version{1, 0}, qmlFileSourceId},
|
||||
Storage::Import{qtQmlModuleId, Storage::Version{6, 0}, qmlFileSourceId},
|
||||
Storage::Import{qmlModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, ImportsWithVersion)
|
||||
{
|
||||
ModuleId fooDirectoryModuleId = storage.moduleId("/path/foo");
|
||||
ModuleId qmlModuleId = storage.moduleId("QML");
|
||||
ModuleId qtQuickModuleId = storage.moduleId("QtQuick");
|
||||
|
||||
auto type = parser.parse(R"(import QtQuick 2.1
|
||||
import "../foo"
|
||||
Example{})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(imports,
|
||||
UnorderedElementsAre(
|
||||
Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{qmlModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{qtQuickModuleId, Storage::Version{2, 1}, qmlFileSourceId}));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, ImportsWithExplictDirectory)
|
||||
{
|
||||
ModuleId qmlModuleId = storage.moduleId("QML");
|
||||
ModuleId qtQuickModuleId = storage.moduleId("QtQuick");
|
||||
|
||||
auto type = parser.parse(R"(import QtQuick
|
||||
import "../to"
|
||||
import "."
|
||||
Example{})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(
|
||||
imports,
|
||||
UnorderedElementsAre(Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{qmlModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, Functions)
|
||||
{
|
||||
auto type = parser.parse(
|
||||
@@ -243,4 +374,162 @@ TEST_F(QmlDocumentParser, Enumeration)
|
||||
ElementsAre(IsEnumerator("On", 0), IsEnumerator("Off", 1))))));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, DISABLED_DuplicateImportsAreRemoved)
|
||||
{
|
||||
ModuleId fooDirectoryModuleId = storage.moduleId("/path/foo");
|
||||
ModuleId qmlModuleId = storage.moduleId("QML");
|
||||
ModuleId qtQmlModuleId = storage.moduleId("QtQml");
|
||||
ModuleId qtQuickModuleId = storage.moduleId("QtQuick");
|
||||
|
||||
auto type = parser.parse(R"(import QtQuick
|
||||
import "../foo"
|
||||
import QtQuick
|
||||
import "../foo"
|
||||
import "/path/foo"
|
||||
import "."
|
||||
|
||||
Example{})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(imports,
|
||||
UnorderedElementsAre(
|
||||
Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId},
|
||||
Storage::Import{qmlModuleId, Storage::Version{1, 0}, qmlFileSourceId},
|
||||
Storage::Import{qtQmlModuleId, Storage::Version{6, 0}, qmlFileSourceId},
|
||||
Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, AliasItemProperties)
|
||||
{
|
||||
auto type = parser.parse(R"(Example{
|
||||
property alias delegate: foo
|
||||
Item {
|
||||
id: foo
|
||||
}
|
||||
})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsPropertyDeclaration("delegate",
|
||||
Storage::ImportedType{"Item"},
|
||||
Storage::PropertyDeclarationTraits::None)));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, AliasProperties)
|
||||
{
|
||||
auto type = parser.parse(R"(Example{
|
||||
property alias text: foo.text2
|
||||
Item {
|
||||
id: foo
|
||||
}
|
||||
})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsAliasPropertyDeclaration("text",
|
||||
Storage::ImportedType{"Item"},
|
||||
Storage::PropertyDeclarationTraits::None,
|
||||
"text2")));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, IndirectAliasProperties)
|
||||
{
|
||||
auto type = parser.parse(R"(Example{
|
||||
property alias textSize: foo.text.size
|
||||
Item {
|
||||
id: foo
|
||||
}
|
||||
})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsAliasPropertyDeclaration("textSize",
|
||||
Storage::ImportedType{"Item"},
|
||||
Storage::PropertyDeclarationTraits::None,
|
||||
"text",
|
||||
"size")));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, InvalidAliasPropertiesAreSkipped)
|
||||
{
|
||||
auto type = parser.parse(R"(Example{
|
||||
property alias textSize: foo2.text.size
|
||||
Item {
|
||||
id: foo
|
||||
}
|
||||
})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations, IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, ListProperty)
|
||||
{
|
||||
auto type = parser.parse(R"(Item{
|
||||
property list<Foo> foos
|
||||
})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(
|
||||
IsPropertyDeclaration("foos",
|
||||
Storage::ImportedType{"Foo"},
|
||||
Storage::PropertyDeclarationTraits::IsList)));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, AliasOnListProperty)
|
||||
{
|
||||
auto type = parser.parse(R"(Item{
|
||||
property alias foos: foo.foos
|
||||
|
||||
Item {
|
||||
id: foo
|
||||
property list<Foo> foos
|
||||
}
|
||||
})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(
|
||||
IsPropertyDeclaration("foos",
|
||||
Storage::ImportedType{"Foo"},
|
||||
Storage::PropertyDeclarationTraits::IsList)));
|
||||
}
|
||||
|
||||
TEST_F(QmlDocumentParser, QualifiedListProperty)
|
||||
{
|
||||
auto exampleModuleId = storage.moduleId("Example");
|
||||
auto type = parser.parse(R"(import Example 2.1 as Example
|
||||
Item{
|
||||
property list<Example.Foo> foos
|
||||
})",
|
||||
imports,
|
||||
qmlFileSourceId,
|
||||
directoryPath);
|
||||
|
||||
ASSERT_THAT(type.propertyDeclarations,
|
||||
UnorderedElementsAre(IsPropertyDeclaration(
|
||||
"foos",
|
||||
Storage::QualifiedImportedType{"Foo",
|
||||
Storage::Import{exampleModuleId,
|
||||
Storage::Version{2, 1},
|
||||
qmlFileSourceId}},
|
||||
Storage::PropertyDeclarationTraits::IsList)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@@ -34,6 +34,9 @@ class QmlDocumentParserMock : public QmlDesigner::QmlDocumentParserInterface
|
||||
public:
|
||||
MOCK_METHOD(QmlDesigner::Storage::Type,
|
||||
parse,
|
||||
(const QString &, QmlDesigner::Storage::Imports &),
|
||||
(const QString &sourceContent,
|
||||
QmlDesigner::Storage::Imports &imports,
|
||||
QmlDesigner::SourceId sourceId,
|
||||
Utils::SmallStringView directoryPath),
|
||||
(override));
|
||||
};
|
||||
|
@@ -173,9 +173,10 @@ protected:
|
||||
Storage::Imports imports;
|
||||
Storage::Types types;
|
||||
SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")};
|
||||
ModuleId qtQmlNativeModuleId = storage.moduleId("QtQml-cppnative");
|
||||
QmlDesigner::Storage::ProjectData projectData{qmltypesFileSourceId,
|
||||
qmltypesFileSourceId,
|
||||
storage.moduleId("QtQml-cppnative"),
|
||||
qtQmlNativeModuleId,
|
||||
Storage::FileType::QmlTypes};
|
||||
SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)};
|
||||
ModuleId directoryModuleId{storage.moduleId("path/to/")};
|
||||
@@ -193,13 +194,11 @@ TEST_F(QmlTypesParser, Imports)
|
||||
ASSERT_THAT(
|
||||
imports,
|
||||
UnorderedElementsAre(
|
||||
IsImport(storage.moduleId("QML"), Storage::Version{}, qmltypesFileSourceId),
|
||||
IsImport(storage.moduleId("QML-cppnative"), Storage::Version{}, qmltypesFileSourceId),
|
||||
IsImport(storage.moduleId("QtQml-cppnative"), Storage::Version{}, qmltypesFileSourceId),
|
||||
IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{2, 15}, qmltypesFileSourceId),
|
||||
IsImport(storage.moduleId("QtQuick.Window-cppnative"),
|
||||
Storage::Version{2, 1},
|
||||
qmltypesFileSourceId),
|
||||
IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{6}, qmltypesFileSourceId)));
|
||||
IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{}, qmltypesFileSourceId),
|
||||
IsImport(storage.moduleId("QtQuick.Window-cppnative"), Storage::Version{}, qmltypesFileSourceId),
|
||||
IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{}, qmltypesFileSourceId)));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, Types)
|
||||
@@ -214,11 +213,11 @@ TEST_F(QmlTypesParser, Types)
|
||||
|
||||
ASSERT_THAT(types,
|
||||
UnorderedElementsAre(IsType("QObject",
|
||||
Storage::NativeType{},
|
||||
Storage::ImportedType{},
|
||||
Storage::TypeAccessSemantics::Reference,
|
||||
qmltypesFileSourceId),
|
||||
IsType("QQmlComponent",
|
||||
Storage::NativeType{"QObject"},
|
||||
Storage::ImportedType{"QObject"},
|
||||
Storage::TypeAccessSemantics::Reference,
|
||||
qmltypesFileSourceId)));
|
||||
}
|
||||
@@ -232,16 +231,16 @@ TEST_F(QmlTypesParser, ExportedTypes)
|
||||
}})"};
|
||||
ModuleId qmlModuleId = storage.moduleId("QML");
|
||||
ModuleId qtQmlModuleId = storage.moduleId("QtQml");
|
||||
ModuleId qtQmlNativeModuleId = storage.moduleId("QtQml-cppnative");
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
ElementsAre(Field(
|
||||
&Storage::Type::exportedTypes,
|
||||
ElementsAre(IsExportedType(qmlModuleId, "QtObject", Storage::Version{1, 0}),
|
||||
IsExportedType(qtQmlModuleId, "QtObject", Storage::Version{2, 1}),
|
||||
IsExportedType(qtQmlNativeModuleId, "QObject", Storage::Version{})))));
|
||||
ElementsAre(
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(
|
||||
IsExportedType(qmlModuleId, "QtObject", Storage::Version{1, 0}),
|
||||
IsExportedType(qtQmlModuleId, "QtObject", Storage::Version{2, 1}),
|
||||
IsExportedType(qtQmlNativeModuleId, "QObject", Storage::Version{})))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, Properties)
|
||||
@@ -262,21 +261,69 @@ TEST_F(QmlTypesParser, Properties)
|
||||
&Storage::Type::propertyDeclarations,
|
||||
UnorderedElementsAre(
|
||||
IsPropertyDeclaration("objectName",
|
||||
Storage::NativeType{"string"},
|
||||
Storage::ImportedType{"string"},
|
||||
Storage::PropertyDeclarationTraits::None),
|
||||
IsPropertyDeclaration("target",
|
||||
Storage::NativeType{"QObject"},
|
||||
Storage::ImportedType{"QObject"},
|
||||
Storage::PropertyDeclarationTraits::IsPointer),
|
||||
IsPropertyDeclaration("progress",
|
||||
Storage::NativeType{"double"},
|
||||
Storage::ImportedType{"double"},
|
||||
Storage::PropertyDeclarationTraits::IsReadOnly),
|
||||
IsPropertyDeclaration("targets",
|
||||
Storage::NativeType{"QQuickItem"},
|
||||
Storage::ImportedType{"QQuickItem"},
|
||||
Storage::PropertyDeclarationTraits::IsReadOnly
|
||||
| Storage::PropertyDeclarationTraits::IsList
|
||||
| Storage::PropertyDeclarationTraits::IsPointer)))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, PropertiesWithQualifiedTypes)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "Qt::Vector" }
|
||||
Component { name: "Qt::List" }
|
||||
Component { name: "QObject"
|
||||
Property { name: "values"; type: "Vector" }
|
||||
Property { name: "items"; type: "List" }
|
||||
Property { name: "values2"; type: "Qt::Vector" }
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
Contains(Field(&Storage::Type::propertyDeclarations,
|
||||
UnorderedElementsAre(
|
||||
IsPropertyDeclaration("values",
|
||||
Storage::ImportedType{"Qt::Vector"},
|
||||
Storage::PropertyDeclarationTraits::None),
|
||||
IsPropertyDeclaration("items",
|
||||
Storage::ImportedType{"Qt::List"},
|
||||
Storage::PropertyDeclarationTraits::None),
|
||||
IsPropertyDeclaration("values2",
|
||||
Storage::ImportedType{"Qt::Vector"},
|
||||
Storage::PropertyDeclarationTraits::None)))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, PropertiesWithoutType)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "QObject"
|
||||
Property { name: "objectName"}
|
||||
Property { name: "target"; type: "QObject"; isPointer: true }
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
ElementsAre(
|
||||
Field(&Storage::Type::propertyDeclarations,
|
||||
UnorderedElementsAre(
|
||||
IsPropertyDeclaration("target",
|
||||
Storage::ImportedType{"QObject"},
|
||||
Storage::PropertyDeclarationTraits::IsPointer)))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, Functions)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
@@ -319,6 +366,50 @@ TEST_F(QmlTypesParser, Functions)
|
||||
Field(&Storage::FunctionDeclaration::parameters, IsEmpty()))))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, SkipJavaScriptFunctions)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "QObject"
|
||||
Method {
|
||||
name: "do"
|
||||
isJavaScriptFunction: true
|
||||
}
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types, ElementsAre(Field(&Storage::Type::functionDeclarations, IsEmpty())));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, FunctionsWithQualifiedTypes)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "Qt::Vector" }
|
||||
Component { name: "Qt::List" }
|
||||
Component { name: "QObject"
|
||||
Method {
|
||||
name: "values"
|
||||
Parameter { name: "values"; type: "Vector" }
|
||||
Parameter { name: "items"; type: "List" }
|
||||
Parameter { name: "values2"; type: "Qt::Vector" }
|
||||
}
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
Contains(
|
||||
Field(&Storage::Type::functionDeclarations,
|
||||
UnorderedElementsAre(AllOf(
|
||||
IsFunctionDeclaration("values", ""),
|
||||
Field(&Storage::FunctionDeclaration::parameters,
|
||||
UnorderedElementsAre(IsParameter("values", "Qt::Vector"),
|
||||
IsParameter("items", "Qt::List"),
|
||||
IsParameter("values2", "Qt::Vector"))))))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, Signals)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
@@ -358,6 +449,34 @@ TEST_F(QmlTypesParser, Signals)
|
||||
IsParameter("args", "QQmlV4Function"))))))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, SignalsWithQualifiedTypes)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "Qt::Vector" }
|
||||
Component { name: "Qt::List" }
|
||||
Component { name: "QObject"
|
||||
Signal {
|
||||
name: "values"
|
||||
Parameter { name: "values"; type: "Vector" }
|
||||
Parameter { name: "items"; type: "List" }
|
||||
Parameter { name: "values2"; type: "Qt::Vector" }
|
||||
}
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
Contains(
|
||||
Field(&Storage::Type::signalDeclarations,
|
||||
UnorderedElementsAre(AllOf(
|
||||
IsSignalDeclaration("values"),
|
||||
Field(&Storage::SignalDeclaration::parameters,
|
||||
UnorderedElementsAre(IsParameter("values", "Qt::Vector"),
|
||||
IsParameter("items", "Qt::List"),
|
||||
IsParameter("values2", "Qt::Vector"))))))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, Enumerations)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
@@ -381,7 +500,7 @@ TEST_F(QmlTypesParser, Enumerations)
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
ElementsAre(
|
||||
Contains(
|
||||
Field(&Storage::Type::enumerationDeclarations,
|
||||
UnorderedElementsAre(
|
||||
AllOf(IsEnumeration("NamedColorSpace"),
|
||||
@@ -396,4 +515,185 @@ TEST_F(QmlTypesParser, Enumerations)
|
||||
IsEnumerator("BottomToTop"))))))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, EnumerationIsExportedAsType)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "QObject"
|
||||
Enum {
|
||||
name: "NamedColorSpace"
|
||||
values: [
|
||||
"Unknown",
|
||||
"SRgb",
|
||||
"AdobeRgb",
|
||||
"DisplayP3",
|
||||
]
|
||||
}
|
||||
Enum {
|
||||
name: "VerticalLayoutDirection"
|
||||
values: ["TopToBottom", "BottomToTop"]
|
||||
}
|
||||
exports: ["QML/QtObject 1.0", "QtQml/QtObject 2.1"]
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(
|
||||
types,
|
||||
UnorderedElementsAre(
|
||||
AllOf(IsType("QObject::NamedColorSpace",
|
||||
Storage::ImportedType{},
|
||||
Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum,
|
||||
qmltypesFileSourceId),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
|
||||
"QObject::NamedColorSpace",
|
||||
Storage::Version{})))),
|
||||
AllOf(IsType("QObject::VerticalLayoutDirection",
|
||||
Storage::ImportedType{},
|
||||
Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum,
|
||||
qmltypesFileSourceId),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
|
||||
"QObject::VerticalLayoutDirection",
|
||||
Storage::Version{})))),
|
||||
_));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAlias)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "QObject"
|
||||
Enum {
|
||||
name: "NamedColorSpaces"
|
||||
alias: "NamedColorSpace"
|
||||
values: [
|
||||
"Unknown",
|
||||
"SRgb",
|
||||
"AdobeRgb",
|
||||
"DisplayP3",
|
||||
]
|
||||
}
|
||||
exports: ["QML/QtObject 1.0", "QtQml/QtObject 2.1"]
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
UnorderedElementsAre(
|
||||
AllOf(IsType("QObject::NamedColorSpaces",
|
||||
Storage::ImportedType{},
|
||||
Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum,
|
||||
qmltypesFileSourceId),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
|
||||
"QObject::NamedColorSpace",
|
||||
Storage::Version{}),
|
||||
IsExportedType(qtQmlNativeModuleId,
|
||||
"QObject::NamedColorSpaces",
|
||||
Storage::Version{})))),
|
||||
_));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAliasToo)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "QObject"
|
||||
Enum {
|
||||
name: "NamedColorSpaces"
|
||||
alias: "NamedColorSpace"
|
||||
values: [
|
||||
"Unknown",
|
||||
"SRgb",
|
||||
"AdobeRgb",
|
||||
"DisplayP3",
|
||||
]
|
||||
}
|
||||
Enum {
|
||||
name: "NamedColorSpace"
|
||||
values: [
|
||||
"Unknown",
|
||||
"SRgb",
|
||||
"AdobeRgb",
|
||||
"DisplayP3",
|
||||
]
|
||||
}
|
||||
exports: ["QML/QtObject 1.0", "QtQml/QtObject 2.1"]
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
UnorderedElementsAre(
|
||||
AllOf(IsType("QObject::NamedColorSpaces",
|
||||
Storage::ImportedType{},
|
||||
Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum,
|
||||
qmltypesFileSourceId),
|
||||
Field(&Storage::Type::exportedTypes,
|
||||
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
|
||||
"QObject::NamedColorSpace",
|
||||
Storage::Version{}),
|
||||
IsExportedType(qtQmlNativeModuleId,
|
||||
"QObject::NamedColorSpaces",
|
||||
Storage::Version{})))),
|
||||
_));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, EnumerationIsReferencedByQualifiedName)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "QObject"
|
||||
Property { name: "colorSpace"; type: "NamedColorSpace" }
|
||||
Enum {
|
||||
name: "NamedColorSpace"
|
||||
values: [
|
||||
"Unknown",
|
||||
"SRgb",
|
||||
"AdobeRgb",
|
||||
"DisplayP3",
|
||||
]
|
||||
}
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
Contains(Field(&Storage::Type::propertyDeclarations,
|
||||
ElementsAre(IsPropertyDeclaration(
|
||||
"colorSpace",
|
||||
Storage::ImportedType{"QObject::NamedColorSpace"},
|
||||
Storage::PropertyDeclarationTraits::None)))));
|
||||
}
|
||||
|
||||
TEST_F(QmlTypesParser, AliasEnumerationIsReferencedByQualifiedName)
|
||||
{
|
||||
QString source{R"(import QtQuick.tooling 1.2
|
||||
Module{
|
||||
Component { name: "QObject"
|
||||
Property { name: "colorSpace"; type: "NamedColorSpaces" }
|
||||
Enum {
|
||||
name: "NamedColorSpace"
|
||||
alias: "NamedColorSpaces"
|
||||
values: [
|
||||
"Unknown",
|
||||
"SRgb",
|
||||
"AdobeRgb",
|
||||
"DisplayP3",
|
||||
]
|
||||
}
|
||||
}})"};
|
||||
|
||||
parser.parse(source, imports, types, projectData);
|
||||
|
||||
ASSERT_THAT(types,
|
||||
Contains(Field(&Storage::Type::propertyDeclarations,
|
||||
ElementsAre(IsPropertyDeclaration(
|
||||
"colorSpace",
|
||||
Storage::ImportedType{"QObject::NamedColorSpaces"},
|
||||
Storage::PropertyDeclarationTraits::None)))));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user