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:
Tim Jenssen
2022-06-13 13:23:12 +02:00
parent 6aa826436c
commit c4e94c2c9c
34 changed files with 10581 additions and 4556 deletions

View 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"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.37.2" #define SQLITE_VERSION "3.38.3"
#define SQLITE_VERSION_NUMBER 3037002 #define SQLITE_VERSION_NUMBER 3038003
#define SQLITE_SOURCE_ID "2022-01-06 13:25:41 872ba256cbf61d9290b571c0e6d82a20c224ca3ad82971edc46b29818d5d17a0" #define SQLITE_SOURCE_ID "2022-04-27 12:03:15 9547e2c38a1c6f751a77d4d796894dec4dc5d8f5d79b1cd39e1ffc50df7b3be4"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** 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_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (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 ** 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. ** sqlite3_extended_errcode() might change with each API call.
** Except, there are some interfaces that are guaranteed to never ** Except, there are some interfaces that are guaranteed to never
** change the value of the error code. The error-code preserving ** change the value of the error code. The error-code preserving
** interfaces are: ** interfaces include the following:
** **
** <ul> ** <ul>
** <li> sqlite3_errcode() ** <li> sqlite3_errcode()
** <li> sqlite3_extended_errcode() ** <li> sqlite3_extended_errcode()
** <li> sqlite3_errmsg() ** <li> sqlite3_errmsg()
** <li> sqlite3_errmsg16() ** <li> sqlite3_errmsg16()
** <li> sqlite3_error_offset()
** </ul> ** </ul>
** **
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** ^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 ** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^. ** 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 ** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between ** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces. ** 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 char *sqlite3_errmsg(sqlite3*);
SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
SQLITE_API const char *sqlite3_errstr(int); SQLITE_API const char *sqlite3_errstr(int);
SQLITE_API int sqlite3_error_offset(sqlite3 *db);
/* /*
** CAPI3REF: Prepared Statement Object ** 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 ** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
** read-only no-op if the table already exists, but ** read-only no-op if the table already exists, but
** sqlite3_stmt_readonly() still returns false for such a statement. ** 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); 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 ** ^The sqlite3_value objects that are passed as parameters into the
** implementation of [application-defined SQL functions] are protected. ** 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 ** ^The sqlite3_value object returned by
** [sqlite3_column_value()] is unprotected. ** [sqlite3_column_value()] is unprotected.
** Unprotected sqlite3_value objects may only be used as arguments ** 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 ** even empty strings, are always zero-terminated. ^The return
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. ** 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 ** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
** [unprotected sqlite3_value] object. In a multithreaded environment, ** [unprotected sqlite3_value] object. In a multithreaded environment,
** an unprotected sqlite3_value object may only be used safely with ** 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 ** [application-defined SQL functions] or [virtual tables], not within
** top-level application code. ** 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 ** ^For example, if the internal representation is FLOAT and a text result
** is requested, [sqlite3_snprintf()] is used internally to perform the ** is requested, [sqlite3_snprintf()] is used internally to perform the
** conversion automatically. ^(The following table details the conversions ** 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> TEXT <td> BLOB <td> No change
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL ** <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> ** </table>
** </blockquote>)^ ** </blockquote>)^
** **
@@ -7122,8 +7141,38 @@ struct sqlite3_index_info {
** **
** These macros define the allowed values for the ** These macros define the allowed values for the
** [sqlite3_index_info].aConstraint[].op field. Each value represents ** [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]. ** 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_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4 #define SQLITE_INDEX_CONSTRAINT_GT 4
@@ -7139,6 +7188,8 @@ struct sqlite3_index_info {
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71
#define SQLITE_INDEX_CONSTRAINT_IS 72 #define SQLITE_INDEX_CONSTRAINT_IS 72
#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 #define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
/* /*
@@ -7168,7 +7219,7 @@ struct sqlite3_index_info {
** destructor. ** destructor.
** **
** ^If the third parameter (the pointer to the sqlite3_module object) is ** ^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. ** same name are dropped.
** **
** See also: [sqlite3_drop_modules()] ** 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_SEEK_COUNT 30
#define SQLITE_TESTCTRL_TRACEFLAGS 31 #define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32 #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 ** 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 ** The counter is incremented on the first [sqlite3_step()] call of each
** cycle. ** 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> ** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
** <dd>^This is the approximate number of bytes of heap memory ** <dd>^This is the approximate number of bytes of heap memory
** used to store the prepared statement. ^This value is not actually ** 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_VM_STEP 4
#define SQLITE_STMTSTATUS_REPREPARE 5 #define SQLITE_STMTSTATUS_REPREPARE 5
#define SQLITE_STMTSTATUS_RUN 6 #define SQLITE_STMTSTATUS_RUN 6
#define SQLITE_STMTSTATUS_FILTER_MISS 7
#define SQLITE_STMTSTATUS_FILTER_HIT 8
#define SQLITE_STMTSTATUS_MEMUSED 99 #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 ** 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] ** 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 ** The first argument must be the pointer to the [sqlite3_index_info] object
** first parameter to the xBestIndex() method. The second argument must be ** that is the first parameter to the xBestIndex() method. The second argument
** an index into the aConstraint[] array belonging to the sqlite3_index_info ** must be an index into the aConstraint[] array belonging to the
** structure passed to xBestIndex. This function returns a pointer to a buffer ** sqlite3_index_info structure passed to xBestIndex.
** containing the name of the collation sequence for the corresponding **
** constraint. ** 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); 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>
** &nbsp; for(rc=sqlite3_vtab_in_first(pList, &pVal);
** &nbsp; rc==SQLITE_OK && pVal
** &nbsp; rc=sqlite3_vtab_in_next(pList, &pVal)
** &nbsp; ){
** &nbsp; // do something with pVal
** &nbsp; }
** &nbsp; if( rc!=SQLITE_OK ){
** &nbsp; // an error has occurred
** &nbsp; }
** </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 ** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode} ** KEYWORDS: {conflict resolution mode}

View File

@@ -344,6 +344,13 @@ struct sqlite3_api_routines {
int (*autovacuum_pages)(sqlite3*, int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*)); 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 #define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */ /* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages #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) */ #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

View File

@@ -11,6 +11,7 @@ add_qtc_library(Sqlite
PUBLIC_DEFINES PUBLIC_DEFINES
SQLITE_CORE SQLITE_CORE
DEPENDS Qt5::Core Threads::Threads ${CMAKE_DL_LIBS} DEPENDS Qt5::Core Threads::Threads ${CMAKE_DL_LIBS}
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.2.0
PUBLIC_INCLUDES PUBLIC_INCLUDES
"${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}"
../3rdparty/sqlite ../3rdparty/sqlite

View File

@@ -154,6 +154,10 @@ public:
{ {
} }
BasicSmallString(const std::wstring &wstring)
: BasicSmallString(BasicSmallString::fromQStringView(wstring))
{}
template<typename BeginIterator, template<typename BeginIterator,
typename EndIterator, typename EndIterator,
typename = std::enable_if_t<std::is_same<BeginIterator, EndIterator>::value> 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) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QStringEncoder encoder{QStringEncoder::Utf8}; QStringEncoder encoder{QStringEncoder::Utf8};
constexpr size_type temporaryArraySize = Size * 6;
size_type oldSize = size(); size_type oldSize = size();
size_type newSize = oldSize + static_cast<size_type>(encoder.requiredSpace(string.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)); reserve(optimalCapacity(newSize));
auto newEnd = encoder.appendToBuffer(data() + size(), string); 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; *newEnd = 0;
setSize(newEnd - data()); setSize(newEnd - data());
#else #else

View File

@@ -3,11 +3,28 @@ if (APPLE)
set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/QmlDesigner") set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/QmlDesigner")
endif() 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 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 DEPENDS
QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
Qt5::QuickWidgets Qt5::CorePrivate Sqlite Qt5::Xml Qt5::Svg Qt5::QuickWidgets Qt5::CorePrivate Sqlite Qt5::Xml Qt5::Svg
qmldomlib
DEFINES DEFINES
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner" 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 extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX designercore/instances SOURCES_PREFIX designercore/instances
SOURCES SOURCES

View File

@@ -98,7 +98,8 @@ enum class BasicIdType {
ProjectPartId, ProjectPartId,
Import, Import,
ImportedTypeName, ImportedTypeName,
ExportedTypeName ExportedTypeName,
ModuleExportedImport
}; };
using TypeId = BasicId<BasicIdType::Type>; using TypeId = BasicId<BasicIdType::Type>;
@@ -137,4 +138,7 @@ using ImportedTypeNameIds = std::vector<ImportedTypeNameId>;
using ExportedTypeNameId = BasicId<BasicIdType::ExportedTypeName>; using ExportedTypeNameId = BasicId<BasicIdType::ExportedTypeName>;
using ExportedTypeNameIds = std::vector<ExportedTypeNameId>; using ExportedTypeNameIds = std::vector<ExportedTypeNameId>;
using ModuleExportedImportId = BasicId<BasicIdType::ModuleExportedImport>;
using ModuleExportedImportIds = std::vector<ModuleExportedImportId>;
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -77,6 +77,15 @@ FileStatus FileSystem::fileStatus(SourceId sourceId) const
return FileStatus{sourceId, -1, -1}; 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) void FileSystem::remove(const SourceIds &sourceIds)
{ {
for (SourceId sourceId : sourceIds) for (SourceId sourceId : sourceIds)

View File

@@ -53,6 +53,7 @@ public:
SourceIds directoryEntries(const QString &directoryPath) const override; SourceIds directoryEntries(const QString &directoryPath) const override;
long long lastModified(SourceId sourceId) const override; long long lastModified(SourceId sourceId) const override;
FileStatus fileStatus(SourceId sourceId) const override; FileStatus fileStatus(SourceId sourceId) const override;
QString contentAsQString(const QString &filePath) const override;
void remove(const SourceIds &sourceIds) override; void remove(const SourceIds &sourceIds) override;

View File

@@ -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

View File

@@ -40,6 +40,8 @@
#include <algorithm> #include <algorithm>
#include <tuple> #include <tuple>
#include <type_traits>
#include <utility>
namespace QmlDesigner { namespace QmlDesigner {
@@ -81,7 +83,12 @@ public:
std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end()); std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end());
synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds); 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, synchronizeTypes(package.types,
updatedTypeIds, updatedTypeIds,
insertedAliasPropertyDeclarations, insertedAliasPropertyDeclarations,
@@ -392,11 +399,13 @@ private:
PropertyDeclarationId propertyDeclarationId, PropertyDeclarationId propertyDeclarationId,
ImportedTypeNameId aliasImportedTypeNameId, ImportedTypeNameId aliasImportedTypeNameId,
Utils::SmallString aliasPropertyName, Utils::SmallString aliasPropertyName,
Utils::SmallString aliasPropertyNameTail,
PropertyDeclarationId aliasPropertyDeclarationId = PropertyDeclarationId{}) PropertyDeclarationId aliasPropertyDeclarationId = PropertyDeclarationId{})
: typeId{typeId} : typeId{typeId}
, propertyDeclarationId{propertyDeclarationId} , propertyDeclarationId{propertyDeclarationId}
, aliasImportedTypeNameId{aliasImportedTypeNameId} , aliasImportedTypeNameId{aliasImportedTypeNameId}
, aliasPropertyName{std::move(aliasPropertyName)} , aliasPropertyName{std::move(aliasPropertyName)}
, aliasPropertyNameTail{std::move(aliasPropertyNameTail)}
, aliasPropertyDeclarationId{aliasPropertyDeclarationId} , aliasPropertyDeclarationId{aliasPropertyDeclarationId}
{} {}
@@ -412,6 +421,7 @@ private:
PropertyDeclarationId propertyDeclarationId; PropertyDeclarationId propertyDeclarationId;
ImportedTypeNameId aliasImportedTypeNameId; ImportedTypeNameId aliasImportedTypeNameId;
Utils::SmallString aliasPropertyName; Utils::SmallString aliasPropertyName;
Utils::SmallString aliasPropertyNameTail;
PropertyDeclarationId aliasPropertyDeclarationId; PropertyDeclarationId aliasPropertyDeclarationId;
}; };
@@ -682,32 +692,72 @@ private:
Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove); 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); synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds);
synchronizeDocumentImports(imports, updatedSourceIds, Storage::ImportKind::Import);
synchronizeDocumentImports(imports, updatedSourceIds); synchronizeDocumentImports(moduleDependencies,
updatedModuleDependencySourceIds,
Storage::ImportKind::ModuleDependency);
} }
void deleteDocumentImportsForDeletedDocuments(Storage::Imports &imports, void synchromizeModuleExportedImports(Storage::ModuleExportedImports &moduleExportedImports,
const SourceIds &updatedSourceIds) const ModuleIds &updatedModuleIds)
{ {
SourceIds importSourceIds = Utils::transform<SourceIds>(imports, std::sort(moduleExportedImports.begin(),
[](const Storage::Import &import) { moduleExportedImports.end(),
return import.sourceId; [](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(), return &view.exportedModuleId - &import.exportedModuleId;
updatedSourceIds.end(), };
importSourceIds.begin(),
importSourceIds.end(),
std::back_inserter(documentSourceIdsToBeDeleted));
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 ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const
@@ -736,15 +786,21 @@ private:
auto callback = [&](long long typeId, auto callback = [&](long long typeId,
long long propertyDeclarationId, long long propertyDeclarationId,
long long propertyImportedTypeNameId, long long propertyImportedTypeNameId,
long long aliasPropertyDeclarationId) { long long aliasPropertyDeclarationId,
long long aliasPropertyDeclarationTailId) {
auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>( auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>(
aliasPropertyDeclarationId); aliasPropertyDeclarationId);
Utils::SmallString aliasPropertyNameTail;
if (aliasPropertyDeclarationTailId != -1)
aliasPropertyNameTail = selectPropertyNameStatement.template value<Utils::SmallString>(
aliasPropertyDeclarationTailId);
relinkableAliasPropertyDeclarations relinkableAliasPropertyDeclarations
.emplace_back(TypeId{typeId}, .emplace_back(TypeId{typeId},
PropertyDeclarationId{propertyDeclarationId}, PropertyDeclarationId{propertyDeclarationId},
ImportedTypeNameId{propertyImportedTypeNameId}, ImportedTypeNameId{propertyImportedTypeNameId},
std::move(aliasPropertyName)); std::move(aliasPropertyName),
std::move(aliasPropertyNameTail));
updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId); updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId);
@@ -919,6 +975,20 @@ private:
relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); 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) void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations)
{ {
for (const auto &aliasDeclaration : aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) {
@@ -927,8 +997,9 @@ private:
if (!aliasTypeId) if (!aliasTypeId)
throw TypeNameDoesNotExists{}; throw TypeNameDoesNotExists{};
auto aliasId = fetchPropertyDeclarationIdByTypeIdAndNameUngarded( auto aliasId = fetchAliasId(aliasTypeId,
aliasTypeId, aliasDeclaration.aliasPropertyName); aliasDeclaration.aliasPropertyName,
aliasDeclaration.aliasPropertyNameTail);
updatePropertyDeclarationAliasIdAndTypeNameIdStatement updatePropertyDeclarationAliasIdAndTypeNameIdStatement
.write(&aliasDeclaration.propertyDeclarationId, .write(&aliasDeclaration.propertyDeclarationId,
@@ -973,8 +1044,19 @@ private:
Prototypes &relinkablePrototypes) Prototypes &relinkablePrototypes)
{ {
std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) {
return std::tie(first.moduleId, first.name, first.version) if (first.moduleId < second.moduleId)
< std::tie(second.moduleId, second.name, second.version); 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>( auto range = selectExportedTypesForSourceIdsStatement.template range<Storage::ExportedTypeView>(
@@ -1020,7 +1102,7 @@ private:
&type.typeId); &type.typeId);
} }
} catch (const Sqlite::ConstraintPreventsModification &) { } catch (const Sqlite::ConstraintPreventsModification &) {
throw QmlDesigner::ModuleDoesNotExists{}; throw QmlDesigner::ExportedTypeCannotBeInserted{};
} }
}; };
@@ -1058,7 +1140,8 @@ private:
PropertyDeclarationId{propertyDeclarationId}, PropertyDeclarationId{propertyDeclarationId},
fetchImportedTypeNameId(value.typeName, fetchImportedTypeNameId(value.typeName,
sourceId), sourceId),
std::move(value.aliasPropertyName)); value.aliasPropertyName,
value.aliasPropertyNameTail);
return Sqlite::CallbackControl::Abort; return Sqlite::CallbackControl::Abort;
}; };
@@ -1075,12 +1158,8 @@ private:
if (!propertyTypeId) if (!propertyTypeId)
throw TypeNameDoesNotExists{}; throw TypeNameDoesNotExists{};
auto propertyDeclarationId = insertPropertyDeclarationStatement.template value< auto propertyDeclarationId = insertPropertyDeclarationStatement.template value<PropertyDeclarationId>(
PropertyDeclarationId>(&typeId, &typeId, value.name, &propertyTypeId, to_underlying(value.traits), &propertyImportedTypeNameId);
value.name,
&propertyTypeId,
static_cast<int>(value.traits),
&propertyImportedTypeNameId);
auto nextPropertyDeclarationId = selectPropertyDeclarationIdPrototypeChainDownStatement auto nextPropertyDeclarationId = selectPropertyDeclarationIdPrototypeChainDownStatement
.template value<PropertyDeclarationId>(&typeId, .template value<PropertyDeclarationId>(&typeId,
@@ -1089,7 +1168,7 @@ private:
updateAliasIdPropertyDeclarationStatement.write(&nextPropertyDeclarationId, updateAliasIdPropertyDeclarationStatement.write(&nextPropertyDeclarationId,
&propertyDeclarationId); &propertyDeclarationId);
updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement
.write(&propertyDeclarationId, &propertyTypeId, static_cast<int>(value.traits)); .write(&propertyDeclarationId, &propertyTypeId, to_underlying(value.traits));
} }
} }
@@ -1104,6 +1183,7 @@ private:
fetchImportedTypeNameId(value.typeName, fetchImportedTypeNameId(value.typeName,
sourceId), sourceId),
value.aliasPropertyName, value.aliasPropertyName,
value.aliasPropertyNameTail,
view.aliasId); view.aliasId);
} }
@@ -1125,10 +1205,10 @@ private:
updatePropertyDeclarationStatement.write(&view.id, updatePropertyDeclarationStatement.write(&view.id,
&propertyTypeId, &propertyTypeId,
static_cast<int>(value.traits), to_underlying(value.traits),
&propertyImportedTypeNameId); &propertyImportedTypeNameId);
updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement
.write(&view.id, &propertyTypeId, static_cast<int>(value.traits)); .write(&view.id, &propertyTypeId, to_underlying(value.traits));
propertyDeclarationIds.push_back(view.id); propertyDeclarationIds.push_back(view.id);
return Sqlite::UpdateChange::Update; return Sqlite::UpdateChange::Update;
} }
@@ -1263,7 +1343,38 @@ private:
PropertyCompare<AliasPropertyDeclaration>{}); 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) { std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
return std::tie(first.sourceId, first.moduleId, first.version) return std::tie(first.sourceId, first.moduleId, first.version)
@@ -1271,7 +1382,7 @@ private:
}); });
auto range = selectDocumentImportForSourceIdStatement.template range<Storage::ImportView>( auto range = selectDocumentImportForSourceIdStatement.template range<Storage::ImportView>(
toIntegers(updatedSourceIds)); toIntegers(updatedSourceIds), to_underlying(importKind));
auto compareKey = [](const Storage::ImportView &view, auto compareKey = [](const Storage::ImportView &view,
const Storage::Import &import) -> long long { const Storage::Import &import) -> long long {
@@ -1291,18 +1402,31 @@ private:
}; };
auto insert = [&](const Storage::Import &import) { auto insert = [&](const Storage::Import &import) {
if (import.version.minor) { insertDocumentImport(import, importKind, import.moduleId, ModuleExportedImportId{});
insertDocumentImportWithVersionStatement.write(&import.sourceId, 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.moduleId,
import.version.major.value, import.version.major.value,
import.version.minor.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);
}
}; };
auto update = [](const Storage::ImportView &, const Storage::Import &) { auto update = [](const Storage::ImportView &, const Storage::Import &) {
@@ -1316,7 +1440,7 @@ private:
Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove); Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove);
} }
Utils::PathString createJson(const Storage::ParameterDeclarations &parameters) static Utils::PathString createJson(const Storage::ParameterDeclarations &parameters)
{ {
Utils::PathString json; Utils::PathString json;
json.append("["); json.append("[");
@@ -1334,7 +1458,7 @@ private:
json.append("\"}"); json.append("\"}");
} else { } else {
json.append("\",\"tr\":"); json.append("\",\"tr\":");
json.append(Utils::SmallString::number(static_cast<int>(parameter.traits))); json.append(Utils::SmallString::number(to_underlying(parameter.traits)));
json.append("}"); json.append("}");
} }
} }
@@ -1350,7 +1474,16 @@ private:
std::sort(functionsDeclarations.begin(), std::sort(functionsDeclarations.begin(),
functionsDeclarations.end(), functionsDeclarations.end(),
[](auto &&first, auto &&second) { [](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 auto range = selectFunctionDeclarationsForTypeIdStatement
@@ -1358,7 +1491,13 @@ private:
auto compareKey = [](const Storage::FunctionDeclarationView &view, auto compareKey = [](const Storage::FunctionDeclarationView &view,
const Storage::FunctionDeclaration &value) { 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) { auto insert = [&](const Storage::FunctionDeclaration &value) {
@@ -1371,10 +1510,10 @@ private:
const Storage::FunctionDeclaration &value) { const Storage::FunctionDeclaration &value) {
Utils::PathString signature{createJson(value.parameters)}; Utils::PathString signature{createJson(value.parameters)};
if (value.returnTypeName == view.returnTypeName && signature == view.signature) if (value.returnTypeName == view.returnTypeName)
return Sqlite::UpdateChange::No; return Sqlite::UpdateChange::No;
updateFunctionDeclarationStatement.write(&view.id, value.returnTypeName, signature); updateFunctionDeclarationStatement.write(&view.id, value.returnTypeName);
return Sqlite::UpdateChange::Update; return Sqlite::UpdateChange::Update;
}; };
@@ -1389,7 +1528,16 @@ private:
void synchronizeSignalDeclarations(TypeId typeId, Storage::SignalDeclarations &signalDeclarations) void synchronizeSignalDeclarations(TypeId typeId, Storage::SignalDeclarations &signalDeclarations)
{ {
std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) { 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 auto range = selectSignalDeclarationsForTypeIdStatement
@@ -1397,7 +1545,13 @@ private:
auto compareKey = [](const Storage::SignalDeclarationView &view, auto compareKey = [](const Storage::SignalDeclarationView &view,
const Storage::SignalDeclaration &value) { 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) { auto insert = [&](const Storage::SignalDeclaration &value) {
@@ -1408,14 +1562,7 @@ private:
auto update = [&](const Storage::SignalDeclarationView &view, auto update = [&](const Storage::SignalDeclarationView &view,
const Storage::SignalDeclaration &value) { const Storage::SignalDeclaration &value) {
Utils::PathString signature{createJson(value.parameters)};
if (signature == view.signature)
return Sqlite::UpdateChange::No; return Sqlite::UpdateChange::No;
updateSignalDeclarationStatement.write(&view.id, signature);
return Sqlite::UpdateChange::Update;
}; };
auto remove = [&](const Storage::SignalDeclarationView &view) { auto remove = [&](const Storage::SignalDeclarationView &view) {
@@ -1425,7 +1572,7 @@ private:
Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove); 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; Utils::PathString json;
json.append("{"); json.append("{");
@@ -1513,8 +1660,7 @@ private:
type.typeId = upsertTypeStatement.template value<TypeId>(&type.sourceId, type.typeId = upsertTypeStatement.template value<TypeId>(&type.sourceId,
type.typeName, type.typeName,
static_cast<int>( to_underlying(type.accessSemantics));
type.accessSemantics));
if (!type.typeId) if (!type.typeId)
type.typeId = selectTypeIdBySourceIdAndNameStatement.template value<TypeId>(&type.sourceId, type.typeId = selectTypeIdBySourceIdAndNameStatement.template value<TypeId>(&type.sourceId,
@@ -1661,13 +1807,6 @@ private:
{ {
struct Inspect struct Inspect
{ {
auto operator()(const Storage::NativeType &nativeType)
{
return storage.fetchImportedTypeNameId(Storage::TypeNameKind::Native,
&sourceId,
nativeType.name);
}
auto operator()(const Storage::ImportedType &importedType) auto operator()(const Storage::ImportedType &importedType)
{ {
return storage.fetchImportedTypeNameId(Storage::TypeNameKind::Exported, return storage.fetchImportedTypeNameId(Storage::TypeNameKind::Exported,
@@ -1696,13 +1835,14 @@ private:
Utils::SmallStringView typeName) Utils::SmallStringView typeName)
{ {
auto importedTypeNameId = selectImportedTypeNameIdStatement.template value<ImportedTypeNameId>( auto importedTypeNameId = selectImportedTypeNameIdStatement.template value<ImportedTypeNameId>(
static_cast<int>(kind), id, typeName); to_underlying(kind), id, typeName);
if (importedTypeNameId) if (importedTypeNameId)
return importedTypeNameId; return importedTypeNameId;
return insertImportedTypeNameIdStatement return insertImportedTypeNameIdStatement.template value<ImportedTypeNameId>(to_underlying(kind),
.template value<ImportedTypeNameId>(static_cast<int>(kind), id, typeName); id,
typeName);
} }
TypeId fetchTypeId(ImportedTypeNameId typeNameId) const TypeId fetchTypeId(ImportedTypeNameId typeNameId) const
@@ -1878,6 +2018,7 @@ private:
createEnumerationsTable(database); createEnumerationsTable(database);
createFunctionsTable(database); createFunctionsTable(database);
createSignalsTable(database); createSignalsTable(database);
createModuleExportedImportsTable(database, moduleIdColumn);
createDocumentImportsTable(database, moduleIdColumn); createDocumentImportsTable(database, moduleIdColumn);
createFileStatusesTable(database); createFileStatusesTable(database);
createProjectDatasTable(database); createProjectDatasTable(database);
@@ -1963,10 +2104,17 @@ private:
propertyDeclarationTable, propertyDeclarationTable,
Sqlite::ForeignKeyAction::NoAction, Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Restrict); Sqlite::ForeignKeyAction::Restrict);
auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn(
"aliasPropertyDeclarationTailId",
propertyDeclarationTable,
Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Restrict);
propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn}); propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn}, propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
"aliasPropertyDeclarationId IS NOT NULL"); "aliasPropertyDeclarationId IS NOT NULL");
propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn},
"aliasPropertyDeclarationTailId IS NOT NULL");
propertyDeclarationTable.initialize(database); propertyDeclarationTable.initialize(database);
} }
@@ -2042,10 +2190,10 @@ private:
{Sqlite::PrimaryKey{}}); {Sqlite::PrimaryKey{}});
auto &typeIdColumn = table.addColumn("typeId"); auto &typeIdColumn = table.addColumn("typeId");
auto &nameColumn = table.addColumn("name"); auto &nameColumn = table.addColumn("name");
table.addColumn("signature"); auto &signatureColumn = table.addColumn("signature");
table.addColumn("returnTypeName"); table.addColumn("returnTypeName");
table.addUniqueIndex({typeIdColumn, nameColumn}); table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn});
table.initialize(database); table.initialize(database);
} }
@@ -2058,9 +2206,9 @@ private:
table.addColumn("signalDeclarationId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); table.addColumn("signalDeclarationId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
auto &typeIdColumn = table.addColumn("typeId"); auto &typeIdColumn = table.addColumn("typeId");
auto &nameColumn = table.addColumn("name"); 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); table.initialize(database);
} }
@@ -2082,6 +2230,30 @@ private:
return std::move(modelIdColumn); 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) void createDocumentImportsTable(Database &database, const Sqlite::Column &foreignModuleIdColumn)
{ {
Sqlite::Table table; Sqlite::Table table;
@@ -2093,16 +2265,37 @@ private:
foreignModuleIdColumn, foreignModuleIdColumn,
Sqlite::ForeignKeyAction::NoAction, Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Cascade, 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 &majorVersionColumn = table.addColumn("majorVersion");
auto &minorVersionColumn = table.addColumn("minorVersion"); 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"); "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"); "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"); "majorVersion IS NOT NULL AND minorVersion IS NOT NULL");
table.initialize(database); table.initialize(database);
@@ -2305,7 +2498,7 @@ public:
database}; database};
mutable ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{ mutable ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{
"SELECT name, returnTypeName, signature, functionDeclarationId FROM " "SELECT name, returnTypeName, signature, functionDeclarationId FROM "
"functionDeclarations WHERE typeId=? ORDER BY name", "functionDeclarations WHERE typeId=? ORDER BY name, signature",
database}; database};
mutable ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{ mutable ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{
"SELECT name, returnTypeName, functionDeclarationId FROM " "SELECT name, returnTypeName, functionDeclarationId FROM "
@@ -2320,15 +2513,13 @@ public:
"INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, " "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, "
"?3, ?4)", "?3, ?4)",
database}; database};
WriteStatement<3> updateFunctionDeclarationStatement{ WriteStatement<2> updateFunctionDeclarationStatement{
"UPDATE functionDeclarations SET returnTypeName=?2, signature=?3 WHERE " "UPDATE functionDeclarations SET returnTypeName=?2 WHERE functionDeclarationId=?1", database};
"functionDeclarationId=?1",
database};
WriteStatement<1> deleteFunctionDeclarationStatement{ WriteStatement<1> deleteFunctionDeclarationStatement{
"DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database}; "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database};
mutable ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{ mutable ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{
"SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER " "SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER "
"BY name", "BY name, signature",
database}; database};
mutable ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{ mutable ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{
"SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name", "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 " "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND "
"name=?3", "name=?3",
database}; database};
mutable ReadStatement<5, 1> selectDocumentImportForSourceIdStatement{ mutable ReadStatement<5, 2> selectDocumentImportForSourceIdStatement{
"SELECT importId, sourceId, moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) " "SELECT importId, sourceId, moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) "
"FROM documentImports WHERE sourceId IN carray(?1) ORDER BY sourceId, moduleId, " "FROM documentImports WHERE sourceId IN carray(?1) AND kind=?2 ORDER BY sourceId, "
"majorVersion, minorVersion", "moduleId, majorVersion, minorVersion",
database}; database};
WriteStatement<2> insertDocumentImportWithoutVersionStatement{ WriteStatement<5> insertDocumentImportWithoutVersionStatement{
"INSERT INTO documentImports(sourceId, moduleId) " "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, "
"VALUES (?1, ?2)", "moduleExportedModuleId) VALUES (?1, ?2, ?3, ?4, ?5)",
database}; database};
WriteStatement<3> insertDocumentImportWithMajorVersionStatement{ WriteStatement<6> insertDocumentImportWithMajorVersionStatement{
"INSERT INTO documentImports(sourceId, moduleId, majorVersion) " "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
"VALUES (?1, ?2, ?3)", "moduleExportedModuleId) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
database}; database};
WriteStatement<4> insertDocumentImportWithVersionStatement{ WriteStatement<7> insertDocumentImportWithVersionStatement{
"INSERT INTO documentImports(sourceId, moduleId, majorVersion, minorVersion) " "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
"VALUES (?1, ?2, ?3, ?4)", "minorVersion, moduleExportedModuleId) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
database}; database};
WriteStatement<1> deleteDocumentImportStatement{"DELETE FROM documentImports WHERE importId=?1", WriteStatement<1> deleteDocumentImportStatement{"DELETE FROM documentImports WHERE importId=?1",
database}; database};
@@ -2426,10 +2617,12 @@ public:
"propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT " "propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT "
"NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)", "NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)",
database}; database};
ReadStatement<4, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{ ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
"SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, " "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
"target.propertyDeclarationId FROM propertyDeclarations AS alias JOIN propertyDeclarations " "alias.aliasPropertyDeclarationId, ifnull(alias.aliasPropertyDeclarationTailId, -1) FROM "
"AS target ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId WHERE " "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 " "alias.propertyTypeId=?1 OR target.typeId=?1 OR alias.propertyImportedTypeNameId IN "
"(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) " "(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) "
"WHERE typeId=?1)", "WHERE typeId=?1)",
@@ -2547,7 +2740,9 @@ public:
"SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database}; "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database};
mutable ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{ mutable ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{
"SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " "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 " "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 " "(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, " "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 " "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE "
"itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND " "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 " "(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, " "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY di.kind, etn.majorVersion DESC "
"etn.minorVersion DESC NULLS FIRST LIMIT 1", "NULLS FIRST, etn.minorVersion DESC NULLS FIRST LIMIT 1",
database}; database};
WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database}; WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database};
WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database};
@@ -2599,8 +2794,45 @@ public:
"SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE " "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
"projectSourceId=?1", "projectSourceId=?1",
database}; database};
ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{ mutable ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{
"SELECT typeId FROM types WHERE sourceId IN carray(?1)", database}; "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 } // namespace QmlDesigner

View File

@@ -77,6 +77,18 @@ public:
const char *what() const noexcept override { return "The module does not exist!"; } 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 class TypeNameDoesNotExists : std::exception
{ {
public: public:

View File

@@ -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

View File

@@ -34,18 +34,36 @@
#include <tuple> #include <tuple>
#include <vector> #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 { namespace QmlDesigner::Storage {
enum class TypeAccessSemantics : int { None, Reference, Value, Sequence, IsEnum = 1 << 8 }; 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, None = 0,
IsReadOnly = 1 << 0, IsReadOnly = 1 << 0,
IsPointer = 1 << 1, IsPointer = 1 << 1,
IsList = 1 << 2 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 }; 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); 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 class Import
{ {
@@ -161,11 +184,16 @@ public:
&& first.sourceId == second.sourceId; && 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: public:
Version version; Version version;
ModuleId moduleId; ModuleId moduleId;
SourceId sourceId; SourceId sourceId;
Utils::SmallString aliasName;
}; };
using Imports = std::vector<Import>; using Imports = std::vector<Import>;
@@ -195,6 +223,81 @@ public:
Version version; 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 class ImportedType
{ {
public: public:
@@ -209,7 +312,7 @@ public:
} }
public: public:
Utils::SmallString name; TypeNameString name;
}; };
class QualifiedImportedType class QualifiedImportedType
@@ -227,7 +330,7 @@ public:
} }
public: public:
Utils::SmallString name; TypeNameString name;
Import import; Import import;
}; };
@@ -266,6 +369,12 @@ public:
return first.name == second.name; 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: public:
Utils::SmallString name; Utils::SmallString name;
Storage::Version version; Storage::Version version;
@@ -305,24 +414,7 @@ public:
ExportedTypeNameId exportedTypeNameId; ExportedTypeNameId exportedTypeNameId;
}; };
class NativeType using ImportedTypeName = Utils::variant<ImportedType, QualifiedImportedType>;
{
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>;
class EnumeratorDeclaration class EnumeratorDeclaration
{ {
@@ -369,7 +461,7 @@ public:
} }
public: public:
Utils::SmallString name; TypeNameString name;
EnumeratorDeclarations enumeratorDeclarations; EnumeratorDeclarations enumeratorDeclarations;
}; };
@@ -419,7 +511,7 @@ public:
public: public:
Utils::SmallString name; Utils::SmallString name;
Utils::SmallString typeName; TypeNameString typeName;
PropertyDeclarationTraits traits = {}; PropertyDeclarationTraits traits = {};
}; };
@@ -494,7 +586,7 @@ public:
public: public:
Utils::SmallString name; Utils::SmallString name;
Utils::SmallString returnTypeName; TypeNameString returnTypeName;
ParameterDeclarations parameters; ParameterDeclarations parameters;
}; };
@@ -548,10 +640,13 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
ImportedTypeName typeName, ImportedTypeName typeName,
PropertyDeclarationTraits traits, PropertyDeclarationTraits traits,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, typeName{std::move(typeName)} , typeName{std::move(typeName)}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, traits{traits} , traits{traits}
, kind{PropertyKind::Property} , kind{PropertyKind::Property}
{} {}
@@ -559,9 +654,11 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
TypeId propertyTypeId, TypeId propertyTypeId,
PropertyDeclarationTraits traits, PropertyDeclarationTraits traits,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, traits{traits} , traits{traits}
, propertyTypeId{propertyTypeId} , propertyTypeId{propertyTypeId}
, kind{PropertyKind::Property} , kind{PropertyKind::Property}
@@ -570,9 +667,12 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
long long propertyTypeId, long long propertyTypeId,
int traits, int traits,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, traits{static_cast<PropertyDeclarationTraits>(traits)} , traits{static_cast<PropertyDeclarationTraits>(traits)}
, propertyTypeId{propertyTypeId} , propertyTypeId{propertyTypeId}
, kind{PropertyKind::Property} , kind{PropertyKind::Property}
@@ -580,10 +680,13 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
ImportedTypeName aliasTypeName, ImportedTypeName aliasTypeName,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, typeName{std::move(aliasTypeName)} , typeName{std::move(aliasTypeName)}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, kind{PropertyKind::Alias} , kind{PropertyKind::Alias}
{} {}
@@ -591,6 +694,7 @@ public:
{ {
return first.name == second.name && first.typeName == second.typeName return first.name == second.name && first.typeName == second.typeName
&& first.aliasPropertyName == second.aliasPropertyName && first.aliasPropertyName == second.aliasPropertyName
&& first.aliasPropertyNameTail == second.aliasPropertyNameTail
&& first.traits == second.traits && first.kind == second.kind; && first.traits == second.traits && first.kind == second.kind;
} }
@@ -598,6 +702,7 @@ public:
Utils::SmallString name; Utils::SmallString name;
ImportedTypeName typeName; ImportedTypeName typeName;
Utils::SmallString aliasPropertyName; Utils::SmallString aliasPropertyName;
Utils::SmallString aliasPropertyNameTail;
PropertyDeclarationTraits traits = {}; PropertyDeclarationTraits traits = {};
TypeId propertyTypeId; TypeId propertyTypeId;
TypeId typeId; TypeId typeId;
@@ -687,7 +792,7 @@ public:
int accessSemantics, int accessSemantics,
int sourceId) int sourceId)
: typeName{typeName} : typeName{typeName}
, prototype{NativeType{prototype}} , prototype{ImportedType{prototype}}
, accessSemantics{static_cast<TypeAccessSemantics>(accessSemantics)} , accessSemantics{static_cast<TypeAccessSemantics>(accessSemantics)}
, sourceId{sourceId} , sourceId{sourceId}
@@ -716,7 +821,7 @@ public:
} }
public: public:
Utils::SmallString typeName; TypeNameString typeName;
ImportedTypeName prototype; ImportedTypeName prototype;
ExportedTypes exportedTypes; ExportedTypes exportedTypes;
PropertyDeclarations propertyDeclarations; PropertyDeclarations propertyDeclarations;
@@ -774,6 +879,18 @@ public:
, updatedSourceIds(std::move(updatedSourceIds)) , 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) SynchronizationPackage(Types types)
: types{std::move(types)} : types{std::move(types)}
{} {}
@@ -800,6 +917,10 @@ public:
FileStatuses fileStatuses; FileStatuses fileStatuses;
ProjectDatas projectDatas; ProjectDatas projectDatas;
SourceIds updatedProjectSourceIds; SourceIds updatedProjectSourceIds;
Imports moduleDependencies;
SourceIds updatedModuleDependencySourceIds;
ModuleExportedImports moduleExportedImports;
ModuleIds updatedModuleIds;
}; };
} // namespace QmlDesigner::Storage } // namespace QmlDesigner::Storage

View File

@@ -27,19 +27,55 @@
#include "filestatuscache.h" #include "filestatuscache.h"
#include "filesysteminterface.h" #include "filesysteminterface.h"
#include "projectmanagerinterface.h"
#include "projectstorage.h" #include "projectstorage.h"
#include "qmldocumentparserinterface.h" #include "qmldocumentparserinterface.h"
#include "qmltypesparserinterface.h" #include "qmltypesparserinterface.h"
#include "sourcepath.h"
#include "sourcepathcache.h" #include "sourcepathcache.h"
#include <sqlitedatabase.h> #include <sqlitedatabase.h>
#include <algorithm>
#include <functional> #include <functional>
namespace QmlDesigner { namespace QmlDesigner {
namespace { 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 createComponentReferences(const QMultiHash<QString, QmlDirParser::Component> &components)
{ {
ComponentReferences componentReferences; ComponentReferences componentReferences;
@@ -78,18 +114,108 @@ void addSourceIds(SourceIds &sourceIds, const Storage::ProjectDatas &projectData
sourceIds.push_back(projectData.sourceId); 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 } // namespace
void ProjectUpdater::update() void ProjectStorageUpdater::update(QStringList qmlDirs, QStringList qmlTypesPaths)
{ {
Storage::SynchronizationPackage package; Storage::SynchronizationPackage package;
SourceIds notUpdatedFileStatusSourceIds; SourceIds notUpdatedFileStatusSourceIds;
SourceIds notUpdatedSourceIds; 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 &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds)
{
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 &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds)
{
for (const QString &qmldirPath : qmlDirs) {
SourcePath qmldirSourcePath{qmldirPath}; SourcePath qmldirSourcePath{qmldirPath};
SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath); SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath);
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
Utils::PathString directoryPath = m_pathCache.sourceContextPath(directoryId);
auto state = fileState(qmlDirSourceId, auto state = fileState(qmlDirSourceId,
package.fileStatuses, package.fileStatuses,
@@ -102,26 +228,43 @@ void ProjectUpdater::update()
package.updatedSourceIds.push_back(qmlDirSourceId); package.updatedSourceIds.push_back(qmlDirSourceId);
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
Utils::PathString moduleName{parser.typeNamespace()}; Utils::PathString moduleName{parser.typeNamespace()};
ModuleId moduleId = m_projectStorage.moduleId(moduleName); 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); const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
addSourceIds(package.updatedSourceIds, qmlProjectDatas); addSourceIds(package.updatedSourceIds, qmlProjectDatas);
addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas); addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas);
parseTypeInfos(parser.typeInfos(), auto qmlTypes = filterMultipleEntries(parser.typeInfos());
if (!qmlTypes.isEmpty()) {
parseTypeInfos(qmlTypes,
filterMultipleEntries(parser.dependencies()),
imports,
qmlDirSourceId, qmlDirSourceId,
directoryId, directoryPath,
moduleId, cppModuleId,
package, package,
notUpdatedFileStatusSourceIds, notUpdatedFileStatusSourceIds,
notUpdatedSourceIds); notUpdatedSourceIds);
}
parseQmlComponents(createComponentReferences(parser.components()), parseQmlComponents(createComponentReferences(parser.components()),
qmlDirSourceId, qmlDirSourceId,
directoryId, directoryId,
moduleId, moduleId,
pathModuleId,
package, package,
notUpdatedFileStatusSourceIds); notUpdatedFileStatusSourceIds);
package.updatedProjectSourceIds.push_back(qmlDirSourceId); package.updatedProjectSourceIds.push_back(qmlDirSourceId);
@@ -130,7 +273,7 @@ void ProjectUpdater::update()
case FileState::NotChanged: { case FileState::NotChanged: {
const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId); const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
parseTypeInfos(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds); parseTypeInfos(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds); parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, directoryPath);
break; break;
} }
case FileState::NotExists: { 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, void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
const QList<QmlDirParser::Import> &qmldirDependencies,
const QList<QmlDirParser::Import> &qmldirImports,
SourceId qmldirSourceId, SourceId qmldirSourceId,
SourceContextId directoryId, Utils::SmallStringView directoryPath,
ModuleId moduleId, ModuleId moduleId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds, SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds) SourceIds &notUpdatedSourceIds)
{ {
QString directory{m_pathCache.sourceContextPath(directoryId)};
for (const QString &typeInfo : typeInfos) { for (const QString &typeInfo : typeInfos) {
SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo}); Utils::PathString qmltypesPath = Utils::PathString::join(
QString qmltypesPath = directory + "/" + typeInfo; {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, auto projectData = package.projectDatas.emplace_back(qmldirSourceId,
sourceId, sourceId,
@@ -182,7 +326,7 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
} }
} }
void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas, void ProjectStorageUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds, SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds) SourceIds &notUpdatedSourceIds)
@@ -191,7 +335,7 @@ void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
if (projectData.fileType != Storage::FileType::QmlTypes) if (projectData.fileType != Storage::FileType::QmlTypes)
continue; continue;
QString qmltypesPath = m_pathCache.sourcePath(projectData.sourceId).toQString(); auto qmltypesPath = m_pathCache.sourcePath(projectData.sourceId);
parseTypeInfo(projectData, parseTypeInfo(projectData,
qmltypesPath, qmltypesPath,
@@ -201,11 +345,11 @@ void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
} }
} }
void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData, auto ProjectStorageUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
const QString &qmltypesPath, Utils::SmallStringView qmltypesPath,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds, SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds) SourceIds &notUpdatedSourceIds) -> FileState
{ {
auto state = fileState(projectData.sourceId, auto state = fileState(projectData.sourceId,
package.fileStatuses, package.fileStatuses,
@@ -215,7 +359,7 @@ void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
case FileState::Changed: { case FileState::Changed: {
package.updatedSourceIds.push_back(projectData.sourceId); 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); m_qmlTypesParser.parse(content, package.imports, package.types, projectData);
break; break;
} }
@@ -226,19 +370,23 @@ void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
case FileState::NotExists: case FileState::NotExists:
break; break;
} }
return state;
} }
void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName, void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFilePath,
Utils::SmallStringView directory, Utils::SmallStringView directoryPath,
Utils::SmallStringView typeName, Storage::ExportedTypes exportedTypes,
Storage::Version version,
ModuleId moduleId, ModuleId moduleId,
SourceId qmldirSourceId, SourceId qmldirSourceId,
SourceContextId directoryId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds) SourceIds &notUpdatedFileStatusSourceIds)
{ {
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; Storage::Type type;
@@ -253,9 +401,8 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
case FileState::NotExists: case FileState::NotExists:
throw CannotParseQmlDocumentFile{}; throw CannotParseQmlDocumentFile{};
case FileState::Changed: case FileState::Changed:
const auto content = m_fileSystem.contentAsQString( const auto content = m_fileSystem.contentAsQString(QString{qmlFilePath});
QString{Utils::PathString{directory} + "/" + fileName}); type = m_qmlDocumentParser.parse(content, package.imports, sourceId, directoryPath);
type = m_qmlDocumentParser.parse(content, package.imports);
break; break;
} }
@@ -263,16 +410,17 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
package.updatedSourceIds.push_back(sourceId); package.updatedSourceIds.push_back(sourceId);
type.typeName = fileName; type.typeName = SourcePath{qmlFilePath}.name();
type.accessSemantics = Storage::TypeAccessSemantics::Reference; type.accessSemantics = Storage::TypeAccessSemantics::Reference;
type.sourceId = sourceId; type.sourceId = sourceId;
type.exportedTypes.push_back(Storage::ExportedType{moduleId, typeName, version}); type.exportedTypes = std::move(exportedTypes);
package.types.push_back(std::move(type)); package.types.push_back(std::move(type));
} }
void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName, void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView filePath, Utils::SmallStringView filePath,
Utils::SmallStringView directoryPath,
SourceId sourceId, SourceId sourceId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds) SourceIds &notUpdatedFileStatusSourceIds)
@@ -286,8 +434,10 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
package.updatedSourceIds.push_back(sourceId); package.updatedSourceIds.push_back(sourceId);
SourcePath sourcePath{filePath};
const auto content = m_fileSystem.contentAsQString(QString{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.typeName = fileName;
type.accessSemantics = Storage::TypeAccessSemantics::Reference; type.accessSemantics = Storage::TypeAccessSemantics::Reference;
@@ -297,43 +447,111 @@ void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
package.types.push_back(std::move(type)); package.types.push_back(std::move(type));
} }
void ProjectUpdater::parseQmlComponents(ComponentReferences components, namespace {
class ComponentReferencesRange
{
public:
using const_iterator = ComponentReferences::const_iterator;
ComponentReferencesRange(const_iterator begin, const_iterator end)
: m_begin{begin}
, m_end{end}
{}
std::size_t size() const { return static_cast<std::size_t>(std::distance(m_begin, m_end)); }
const_iterator begin() const { return m_begin; }
const_iterator end() const { return m_end; }
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;
}
}
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, SourceId qmldirSourceId,
SourceContextId directoryId, SourceContextId directoryId,
ModuleId moduleId, ModuleId moduleId,
ModuleId pathModuleId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds) SourceIds &notUpdatedFileStatusSourceIds)
{ {
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) { std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion) return std::tie(first.get().fileName,
> std::tie(second.get().typeName, second.get().majorVersion, second.get().minorVersion); first.get().typeName,
first.get().majorVersion,
first.get().minorVersion)
> std::tie(first.get().fileName,
second.get().typeName,
second.get().majorVersion,
second.get().minorVersion);
}); });
auto newEnd = std::unique(components.begin(), components.end(), [](auto &&first, auto &&second) { auto directoryPath = m_pathCache.sourceContextPath(directoryId);
return first.get().typeName == second.get().typeName
&& first.get().majorVersion == second.get().majorVersion;
});
components.erase(newEnd, components.end()); auto callback = [&](ComponentReferencesRange componentsWithSameFileName) {
const auto &firstComponent = *componentsWithSameFileName.begin();
auto directory = m_pathCache.sourceContextPath(directoryId); const Utils::SmallString fileName{firstComponent.get().fileName};
parseQmlComponent(fileName,
for (const QmlDirParser::Component &component : components) { directoryPath,
parseQmlComponent(Utils::SmallString{component.fileName}, createExportedTypes(componentsWithSameFileName, moduleId, fileName, pathModuleId),
directory,
Utils::SmallString{component.typeName},
Storage::Version{component.majorVersion, component.minorVersion},
moduleId, moduleId,
qmldirSourceId, qmldirSourceId,
directoryId,
package, package,
notUpdatedFileStatusSourceIds); notUpdatedFileStatusSourceIds);
} };
partitionForTheSameFileName(components, callback);
} }
void ProjectUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas, void ProjectStorageUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds) SourceIds &notUpdatedFileStatusSourceIds,
Utils::SmallStringView directoryPath)
{ {
for (const Storage::ProjectData &projectData : projectDatas) { for (const Storage::ProjectData &projectData : projectDatas) {
if (projectData.fileType != Storage::FileType::QmlDocument) if (projectData.fileType != Storage::FileType::QmlDocument)
@@ -343,13 +561,14 @@ void ProjectUpdater::parseQmlComponents(const Storage::ProjectDatas &projectData
parseQmlComponent(qmlDocumentPath.name(), parseQmlComponent(qmlDocumentPath.name(),
qmlDocumentPath, qmlDocumentPath,
directoryPath,
projectData.sourceId, projectData.sourceId,
package, package,
notUpdatedFileStatusSourceIds); notUpdatedFileStatusSourceIds);
} }
} }
ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId, ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState(SourceId sourceId,
FileStatuses &fileStatuses, FileStatuses &fileStatuses,
SourceIds &updatedSourceIds, SourceIds &updatedSourceIds,
SourceIds &notUpdatedSourceIds) const SourceIds &notUpdatedSourceIds) const

View File

@@ -42,7 +42,6 @@ class Database;
} }
namespace QmlDesigner { namespace QmlDesigner {
class ProjectManagerInterface;
class FileSystemInterface; class FileSystemInterface;
class ProjectStorageInterface; class ProjectStorageInterface;
template<typename ProjectStorage, typename Mutex> template<typename ProjectStorage, typename Mutex>
@@ -53,22 +52,21 @@ class ProjectStorage;
class QmlDocumentParserInterface; class QmlDocumentParserInterface;
class QmlTypesParserInterface; 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: public:
using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>; using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>;
ProjectUpdater(ProjectManagerInterface &projectManager, ProjectStorageUpdater(FileSystemInterface &fileSystem,
FileSystemInterface &fileSystem,
ProjectStorageInterface &projectStorage, ProjectStorageInterface &projectStorage,
FileStatusCache &fileStatusCache, FileStatusCache &fileStatusCache,
PathCache &pathCache, PathCache &pathCache,
QmlDocumentParserInterface &qmlDocumentParser, QmlDocumentParserInterface &qmlDocumentParser,
QmlTypesParserInterface &qmlTypesParser) QmlTypesParserInterface &qmlTypesParser)
: m_projectManager{projectManager} : m_fileSystem{fileSystem}
, m_fileSystem{fileSystem}
, m_projectStorage{projectStorage} , m_projectStorage{projectStorage}
, m_fileStatusCache{fileStatusCache} , m_fileStatusCache{fileStatusCache}
, m_pathCache{pathCache} , m_pathCache{pathCache}
@@ -76,7 +74,7 @@ public:
, m_qmlTypesParser{qmlTypesParser} , m_qmlTypesParser{qmlTypesParser}
{} {}
void update(); void update(QStringList qmlDirs, QStringList qmlTypesPaths);
void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths); void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths);
private: private:
@@ -86,9 +84,20 @@ private:
NotExists, NotExists,
}; };
void updateQmlTypes(const QStringList &qmlTypesPaths,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds);
void updateQmldirs(const QStringList &qmlDirs,
Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds);
void parseTypeInfos(const QStringList &typeInfos, void parseTypeInfos(const QStringList &typeInfos,
const QList<QmlDirParser::Import> &qmldirDependencies,
const QList<QmlDirParser::Import> &qmldirImports,
SourceId qmldirSourceId, SourceId qmldirSourceId,
SourceContextId directoryId, Utils::SmallStringView directoryPath,
ModuleId moduleId, ModuleId moduleId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds, SourceIds &notUpdatedFileStatusSourceIds,
@@ -97,8 +106,8 @@ private:
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds, SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds); SourceIds &notUpdatedSourceIds);
void parseTypeInfo(const Storage::ProjectData &projectData, FileState parseTypeInfo(const Storage::ProjectData &projectData,
const QString &qmltypesPath, Utils::SmallStringView qmltypesPath,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds, SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds); SourceIds &notUpdatedSourceIds);
@@ -106,22 +115,23 @@ private:
SourceId qmldirSourceId, SourceId qmldirSourceId,
SourceContextId directoryId, SourceContextId directoryId,
ModuleId moduleId, ModuleId moduleId,
ModuleId pathModuleId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds); SourceIds &notUpdatedFileStatusSourceIds);
void parseQmlComponents(const Storage::ProjectDatas &projectDatas, void parseQmlComponents(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds); SourceIds &notUpdatedFileStatusSourceIds,
Utils::SmallStringView directoryPath);
void parseQmlComponent(Utils::SmallStringView fileName, void parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView directory, Utils::SmallStringView directory,
Utils::SmallStringView typeName, Storage::ExportedTypes exportedTypes,
Storage::Version version,
ModuleId moduleId, ModuleId moduleId,
SourceId qmldirSourceId, SourceId qmldirSourceId,
SourceContextId directoryId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds); SourceIds &notUpdatedFileStatusSourceIds);
void parseQmlComponent(Utils::SmallStringView fileName, void parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView filePath, Utils::SmallStringView filePath,
Utils::SmallStringView directoryPath,
SourceId sourceId, SourceId sourceId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds); SourceIds &notUpdatedFileStatusSourceIds);
@@ -132,7 +142,6 @@ private:
SourceIds &notUpdatedSourceIds) const; SourceIds &notUpdatedSourceIds) const;
private: private:
ProjectManagerInterface &m_projectManager;
FileSystemInterface &m_fileSystem; FileSystemInterface &m_fileSystem;
ProjectStorageInterface &m_projectStorage; ProjectStorageInterface &m_projectStorage;
FileStatusCache &m_fileStatusCache; FileStatusCache &m_fileStatusCache;

View File

@@ -1,3 +1,4 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2021 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
@@ -26,6 +27,7 @@
#include "qmldocumentparser.h" #include "qmldocumentparser.h"
#include "projectstorage.h" #include "projectstorage.h"
#include "projectstorageexceptions.h"
#include "sourcepathcache.h" #include "sourcepathcache.h"
#include <sqlitedatabase.h> #include <sqlitedatabase.h>
@@ -45,6 +47,8 @@ namespace QmlDom = QQmlJS::Dom;
namespace { namespace {
using QualifiedImports = std::map<QString, Storage::Import>;
int convertVersionNumber(qint32 versionNumber) int convertVersionNumber(qint32 versionNumber)
{ {
return versionNumber < 0 ? -1 : versionNumber; return versionNumber < 0 ? -1 : versionNumber;
@@ -56,46 +60,189 @@ Storage::Version convertVersion(QmlDom::Version version)
convertVersionNumber(version.minorVersion)}; 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{ modulePath /= relativePath.toStdString();
std::u16string_view{localPath.utf16(), static_cast<std::size_t>(localPath.size())}};
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, void addImports(Storage::Imports &imports,
const QList<QmlDom::Import> &qmlImports, const QList<QmlDom::Import> &qmlImports,
SourceId sourceId, SourceId sourceId,
const QString &directoryPath, Utils::SmallStringView directoryPath,
QmlDocumentParser::ProjectStorage &storage) QmlDocumentParser::ProjectStorage &storage)
{ {
int importCount = 0;
for (const QmlDom::Import &qmlImport : qmlImports) { for (const QmlDom::Import &qmlImport : qmlImports) {
if (qmlImport.uri == u"file://.") { if (!qmlImport.implicit) {
auto moduleId = storage.moduleId(Utils::PathString{directoryPath}); imports.push_back(createImport(qmlImport, sourceId, directoryPath, storage));
imports.emplace_back(moduleId, Storage::Version{}, sourceId); ++importCount;
} 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);
}
} }
} }
void addPropertyDeclarations(Storage::Type &type, const QmlDom::QmlObject &rootObject) 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);
}
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()) { for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) {
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}, type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
Storage::ImportedType{ std::move(importedTypeName),
Utils::SmallString{propertyDeclaration.typeName}}, traits,
Storage::PropertyDeclarationTraits::None); 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::Type QmlDocumentParser::parse(const QString &sourceContent,
Storage::Imports &imports, Storage::Imports &imports,
SourceId sourceId, SourceId sourceId,
const QString &directoryPath) Utils::SmallStringView directoryPath)
{ {
Storage::Type type; Storage::Type type;
QmlDom::DomItem environment = QmlDom::DomEnvironment::create( using Option = QmlDom::DomEnvironment::Option;
{},
QmlDom::DomEnvironment::Option::SingleThreaded QmlDom::DomItem environment = QmlDom::DomEnvironment::create({},
| QmlDom::DomEnvironment::Option::NoDependencies); Option::SingleThreaded
| Option::NoDependencies
| Option::WeakLoad);
QmlDom::DomItem items; QmlDom::DomItem items;
QString filePath{directoryPath + "/foo.qml"}; QString filePath{m_pathCache.sourcePath(sourceId)};
environment.loadFile( environment.loadFile(
filePath, filePath,
@@ -181,18 +330,25 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
return type; return type;
const auto &component = components.first(); const auto &component = components.first();
const auto &objects = component.objects(); auto objects = component.objects();
if (objects.empty()) if (objects.empty())
return type; 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); addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
addPropertyDeclarations(type, qmlObject); addPropertyDeclarations(type, qmlObject, qualifiedImports, file);
addFunctionAndSignalDeclarations(type, qmlObject); addFunctionAndSignalDeclarations(type, qmlObject);
addEnumeraton(type, component); addEnumeraton(type, component);

View File

@@ -40,22 +40,24 @@ class ProjectStorage;
template<typename ProjectStorage, typename Mutex> template<typename ProjectStorage, typename Mutex>
class SourcePathCache; class SourcePathCache;
class QmlDocumentParser class QmlDocumentParser : public QmlDocumentParserInterface
{ {
public: public:
using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>; using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>;
QmlDocumentParser(ProjectStorage &storage) QmlDocumentParser(ProjectStorage &storage, PathCache &pathCache)
: m_storage{storage} : m_storage{storage}
, m_pathCache{pathCache}
{} {}
Storage::Type parse(const QString &sourceContent, Storage::Type parse(const QString &sourceContent,
Storage::Imports &imports, Storage::Imports &imports,
SourceId sourceId, SourceId sourceId,
const QString &directoryPath); Utils::SmallStringView directoryPath) override;
private: private:
ProjectStorage &m_storage; ProjectStorage &m_storage;
PathCache &m_pathCache;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -34,7 +34,11 @@ namespace QmlDesigner {
class QmlDocumentParserInterface class QmlDocumentParserInterface
{ {
public: 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: protected:
~QmlDocumentParserInterface() = default; ~QmlDocumentParserInterface() = default;

View File

@@ -47,6 +47,29 @@ namespace QmlDom = QQmlJS::Dom;
namespace { 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, void appendImports(Storage::Imports &imports,
const QString &dependency, const QString &dependency,
SourceId sourceId, SourceId sourceId,
@@ -60,43 +83,22 @@ void appendImports(Storage::Imports &imports,
moduleName.append("-cppnative"); moduleName.append("-cppnative");
ModuleId cppModuleId = storage.moduleId(moduleName); ModuleId cppModuleId = storage.moduleId(moduleName);
auto majorVersionFound = std::find_if(spaceFound, dependency.end(), [](QChar c) { imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
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);
} }
void addImports(Storage::Imports &imports, void addImports(Storage::Imports &imports,
SourceId sourceId, SourceId sourceId,
const QStringList &dependencies, const QStringList &dependencies,
QmlTypesParser::ProjectStorage &storage) QmlTypesParser::ProjectStorage &storage,
ModuleId cppModuleId)
{ {
for (const QString &dependency : dependencies) for (const QString &dependency : dependencies)
appendImports(imports, dependency, sourceId, storage); appendImports(imports, dependency, sourceId, storage);
imports.emplace_back(storage.moduleId("QML"), Storage::Version{}, sourceId); imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
imports.emplace_back(storage.moduleId("QtQml-cppnative"), 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) Storage::TypeAccessSemantics createTypeAccessSemantics(QQmlJSScope::AccessSemantics accessSematics)
@@ -121,7 +123,7 @@ Storage::Version createVersion(QTypeRevision qmlVersion)
} }
Storage::ExportedTypes createExports(const QList<QQmlJSScope::Export> &qmlExports, Storage::ExportedTypes createExports(const QList<QQmlJSScope::Export> &qmlExports,
const QQmlJSScope &component, Utils::SmallStringView interanalName,
QmlTypesParser::ProjectStorage &storage, QmlTypesParser::ProjectStorage &storage,
ModuleId cppModuleId) ModuleId cppModuleId)
{ {
@@ -129,12 +131,43 @@ Storage::ExportedTypes createExports(const QList<QQmlJSScope::Export> &qmlExport
exportedTypes.reserve(Utils::usize(qmlExports)); exportedTypes.reserve(Utils::usize(qmlExports));
for (const QQmlJSScope::Export &qmlExport : qmlExports) { for (const QQmlJSScope::Export &qmlExport : qmlExports) {
TypeNameString exportedTypeName{qmlExport.type()};
exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}), exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}),
Utils::SmallString{qmlExport.type()}, std::move(exportedTypeName),
createVersion(qmlExport.version())); 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; return exportedTypes;
} }
@@ -155,22 +188,61 @@ Storage::PropertyDeclarationTraits createPropertyDeclarationTraits(const QQmlJSM
return traits; 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; Storage::PropertyDeclarations propertyDeclarations;
propertyDeclarations.reserve(Utils::usize(qmlProperties)); propertyDeclarations.reserve(Utils::usize(qmlProperties));
for (const QQmlJSMetaProperty &qmlProperty : 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()}, propertyDeclarations.emplace_back(Utils::SmallString{qmlProperty.propertyName()},
Storage::NativeType{ Storage::ImportedType{propertyTypeName},
Utils::SmallString{qmlProperty.typeName()}},
createPropertyDeclarationTraits(qmlProperty)); createPropertyDeclarationTraits(qmlProperty));
} }
return propertyDeclarations; return propertyDeclarations;
} }
Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMethod) Storage::ParameterDeclarations createParameters(
const QQmlJSMetaMethod &qmlMethod, const ComponentWithoutNamespaces &componentNameWithoutNamespace)
{ {
Storage::ParameterDeclarations parameterDeclarations; Storage::ParameterDeclarations parameterDeclarations;
@@ -183,14 +255,16 @@ Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMetho
for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) { for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) {
parameterDeclarations.emplace_back(Utils::SmallString{*currentName}, parameterDeclarations.emplace_back(Utils::SmallString{*currentName},
Utils::SmallString{*currentType}); fullyQualifiedTypeName(*currentType,
componentNameWithoutNamespace));
} }
return parameterDeclarations; return parameterDeclarations;
} }
std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFunctionAndSignals( 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; std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> functionAndSignalDeclarations;
Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)}; Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)};
@@ -199,13 +273,18 @@ std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFun
signalDeclarations.reserve(Utils::usize(qmlMethods)); signalDeclarations.reserve(Utils::usize(qmlMethods));
for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) { for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) {
if (qmlMethod.isJavaScriptFunction())
continue;
if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) { if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) {
functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()},
Utils::SmallString{qmlMethod.returnTypeName()}, fullyQualifiedTypeName(qmlMethod.returnTypeName(),
createParameters(qmlMethod)); componentNameWithoutNamespace),
createParameters(qmlMethod,
componentNameWithoutNamespace));
} else { } else {
signalDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, 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)); enumerationDeclarations.reserve(Utils::usize(qmlEnumerations));
for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) { for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) {
enumerationDeclarations.emplace_back(Utils::SmallString{qmlEnumeration.name()}, enumerationDeclarations.emplace_back(TypeNameString{qmlEnumeration.name()},
createEnumerators(qmlEnumeration)); createEnumerators(qmlEnumeration));
} }
return enumerationDeclarations; 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, void addType(Storage::Types &types,
SourceId sourceId, SourceId sourceId,
ModuleId cppModuleId, ModuleId cppModuleId,
const QQmlJSScope &component, const QQmlJSExportedScope &exportScope,
QmlTypesParser::ProjectStorage &storage) QmlTypesParser::ProjectStorage &storage,
const ComponentWithoutNamespaces &componentNameWithoutNamespace)
{ {
auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(component.ownMethods()); const auto &component = *exportScope.scope;
types.emplace_back(Utils::SmallString{component.internalName()},
Storage::NativeType{Utils::SmallString{component.baseTypeName()}}, 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()), createTypeAccessSemantics(component.accessSemantics()),
sourceId, sourceId,
createExports(component.exports(), component, storage, cppModuleId), createExports(exports, typeName, storage, cppModuleId),
createProperties(component.ownProperties()), createProperties(component.ownProperties(),
enumerationTypes,
componentNameWithoutNamespace),
std::move(functionsDeclarations), std::move(functionsDeclarations),
std::move(signalDeclarations), std::move(signalDeclarations),
createEnumeration(component.ownEnumerations())); createEnumeration(enumerations));
} }
void addTypes(Storage::Types &types, void addTypes(Storage::Types &types,
const Storage::ProjectData &projectData, const Storage::ProjectData &projectData,
const QHash<QString, QQmlJSScope::Ptr> &objects, const QHash<QString, QQmlJSExportedScope> &objects,
QmlTypesParser::ProjectStorage &storage) QmlTypesParser::ProjectStorage &storage,
const ComponentWithoutNamespaces &componentNameWithoutNamespaces)
{ {
types.reserve(Utils::usize(objects) + types.size()); types.reserve(Utils::usize(objects) + types.size());
for (const auto &object : objects) for (const auto &object : objects)
addType(types, projectData.sourceId, projectData.moduleId, *object.get(), storage); addType(types,
projectData.sourceId,
projectData.moduleId,
object,
storage,
componentNameWithoutNamespaces);
} }
} // namespace } // namespace
@@ -297,14 +466,16 @@ void QmlTypesParser::parse(const QString &sourceContent,
const Storage::ProjectData &projectData) const Storage::ProjectData &projectData)
{ {
QQmlJSTypeDescriptionReader reader({}, sourceContent); QQmlJSTypeDescriptionReader reader({}, sourceContent);
QHash<QString, QQmlJSScope::Ptr> components; QHash<QString, QQmlJSExportedScope> components;
QStringList dependencies; QStringList dependencies;
bool isValid = reader(&components, &dependencies); bool isValid = reader(&components, &dependencies);
if (!isValid) if (!isValid)
throw CannotParseQmlTypesFile{}; throw CannotParseQmlTypesFile{};
addImports(imports, projectData.sourceId, dependencies, m_storage); auto componentNameWithoutNamespaces = createComponentNameWithoutNamespaces(components);
addTypes(types, projectData, components, m_storage);
addImports(imports, projectData.sourceId, dependencies, m_storage, projectData.moduleId);
addTypes(types, projectData, components, m_storage, componentNameWithoutNamespaces);
} }
#else #else

View File

@@ -121,15 +121,43 @@ public:
Sqlite::JournalMode::Wal, Sqlite::JournalMode::Wal,
Sqlite::LockingMode::Normal}; Sqlite::LockingMode::Normal};
ImageCacheStorage<Sqlite::Database> storage{database}; ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager,
QSize{300, 300},
QSize{1000, 1000},
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
TimeStampProvider timeStampProvider;
AsynchronousExplicitImageCache cache{storage}; 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 class QmlDesignerProjectManager::QmlDesignerProjectManagerProjectData
{ {
public: public:
QmlDesignerProjectManagerProjectData(ImageCacheStorage<Sqlite::Database> &storage) QmlDesignerProjectManagerProjectData(ImageCacheStorage<Sqlite::Database> &storage,
::ProjectExplorer::Project *project)
: factory{storage, timeStampProvider, collector} : factory{storage, timeStampProvider, collector}
, projectStorageData{project}
{} {}
ImageCacheConnectionManager connectionManager; ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager, ImageCacheCollector collector{connectionManager,
QSize{300, 300}, QSize{300, 300},
@@ -137,6 +165,7 @@ public:
ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
TimeStampProvider timeStampProvider; TimeStampProvider timeStampProvider;
AsynchronousImageFactory factory; AsynchronousImageFactory factory;
ProjectStorageData projectStorageData;
::ProjectExplorer::Target *activeTarget = nullptr; ::ProjectExplorer::Target *activeTarget = nullptr;
}; };
@@ -191,24 +220,155 @@ void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *)
m_projectData->activeTarget); m_projectData->activeTarget);
if (qmlBuildSystem) { if (qmlBuildSystem) {
m_projectData->collector.setTarget(m_projectData->activeTarget); m_previewImageCacheData->collector.setTarget(m_projectData->activeTarget);
m_projectData->factory.generate(qmlBuildSystem->mainFilePath().toString().toUtf8()); m_previewImageCacheData->factory.generate(qmlBuildSystem->mainFilePath().toString().toUtf8());
} }
} }
void QmlDesignerProjectManager::editorsClosed(const QList<::Core::IEditor *> &) {} 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) void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project)
{ {
m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_previewImageCacheData->storage); if (qEnvironmentVariableIsSet("QDS_ACTIVATE_PROJECT_STORAGE")) {
m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_previewImageCacheData->storage,
project);
m_projectData->activeTarget = project->activeTarget(); 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 *) void QmlDesignerProjectManager::aboutToRemoveProject(::ProjectExplorer::Project *)
{ {
if (m_projectData) if (m_projectData) {
m_previewImageCacheData->collector.setTarget(m_projectData->activeTarget);
m_projectData.reset(); m_projectData.reset();
} }
}
void QmlDesignerProjectManager::projectRemoved(::ProjectExplorer::Project *) {} void QmlDesignerProjectManager::projectRemoved(::ProjectExplorer::Project *) {}
@@ -244,4 +404,56 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache
return m_imageCacheData.get(); 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 } // namespace QmlDesigner

View File

@@ -69,6 +69,15 @@ private:
void projectRemoved(::ProjectExplorer::Project *project); void projectRemoved(::ProjectExplorer::Project *project);
ImageCacheData *imageCacheData(); ImageCacheData *imageCacheData();
void fileListChanged();
void activeTargetChanged(::ProjectExplorer::Target *target);
void aboutToRemoveTarget(::ProjectExplorer::Target *target);
void kitChanged();
void projectChanged();
private:
void update();
private: private:
std::once_flag imageCacheFlag; std::once_flag imageCacheFlag;
std::unique_ptr<ImageCacheData> m_imageCacheData; std::unique_ptr<ImageCacheData> m_imageCacheData;

View File

@@ -327,6 +327,8 @@ void QmlBuildSystem::refresh(RefreshOptions options)
modelManager->updateProjectInfo(projectInfo, project()); modelManager->updateProjectInfo(projectInfo, project());
guard.markAsSuccess(); guard.markAsSuccess();
emit projectChanged();
} }
QString QmlBuildSystem::mainFile() const QString QmlBuildSystem::mainFile() const
@@ -749,6 +751,20 @@ QStringList QmlBuildSystem::shaderToolFiles() const
return {}; 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 *) bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *)
{ {
if (!dynamic_cast<QmlProjectNode *>(context)) if (!dynamic_cast<QmlProjectNode *>(context))

View File

@@ -103,6 +103,8 @@ public:
bool widgetApp() const; bool widgetApp() const;
QStringList shaderToolArgs() const; QStringList shaderToolArgs() const;
QStringList shaderToolFiles() const; QStringList shaderToolFiles() const;
QStringList importPaths() const;
QStringList files() const;
bool addFiles(const QStringList &filePaths); bool addFiles(const QStringList &filePaths);
@@ -121,6 +123,9 @@ public:
// plain format // plain format
void parseProject(RefreshOptions options); void parseProject(RefreshOptions options);
signals:
void projectChanged();
private: private:
bool setFileSettingInProjectFile(const QString &setting, bool setFileSettingInProjectFile(const QString &setting,
const Utils::FilePath &mainFilePath, const Utils::FilePath &mainFilePath,

View File

@@ -265,7 +265,6 @@ extend_qtc_test(unittest
projectstorage/filestatus.h projectstorage/filestatus.h
projectstorage/filestatuscache.cpp projectstorage/filestatuscache.h projectstorage/filestatuscache.cpp projectstorage/filestatuscache.h
projectstorage/nonlockingmutex.h projectstorage/nonlockingmutex.h
projectstorage/projectmanagerinterface.h
projectstorage/projectstorageinterface.h projectstorage/projectstorageinterface.h
projectstorage/projectstorage.h projectstorage/projectstorage.h
projectstorage/projectstoragepathwatcher.h projectstorage/projectstoragepathwatcher.h
@@ -301,7 +300,6 @@ extend_qtc_test(unittest
filesystemmock.h filesystemmock.h
filestatuscache-test.cpp filestatuscache-test.cpp
listmodeleditor-test.cpp listmodeleditor-test.cpp
projectmanagermock.h
projectstorage-test.cpp projectstorage-test.cpp
projectstorageupdater-test.cpp projectstorageupdater-test.cpp
projectstoragesqlitefunctionregistry-test.cpp projectstoragesqlitefunctionregistry-test.cpp
@@ -378,25 +376,29 @@ get_filename_component(
ABSOLUTE ABSOLUTE
) )
if(EXISTS ${QMLDOM_STANDALONE_CMAKELISTS} AND Qt6_FOUND) if(EXISTS ${QMLDOM_STANDALONE_CMAKELISTS} AND Qt6_FOUND AND NOT TARGET qmldomlib)
add_subdirectory( add_subdirectory(
../../../../qmldom_standalone/src/qmldom/standalone ../../../../qmldom_standalone/src/qmldom/standalone
${CMAKE_CURRENT_BINARY_DIR}/qmldom_standalone) ${CMAKE_BINARY_DIR}/qmldom_standalone)
set_target_properties(qmldomlib PROPERTIES set_target_properties(qmldomlib PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,RUNTIME_OUTPUT_DIRECTORY>" RUNTIME_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,RUNTIME_OUTPUT_DIRECTORY>"
LIBRARY_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,LIBRARY_OUTPUT_DIRECTORY>") LIBRARY_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,LIBRARY_OUTPUT_DIRECTORY>")
endif()
extend_qtc_test(unittest extend_qtc_test(unittest
CONDITION TARGET qmldomlib
DEPENDS qmldomlib DEPENDS qmldomlib
SOURCES SOURCES
qmldocumentparser-test.cpp qmldocumentparser-test.cpp
qmltypesparser-test.cpp qmltypesparser-test.cpp
) )
extend_qtc_test(unittest extend_qtc_test(unittest
SOURCES_PREFIX "${QmlDesignerDir}/designercore" SOURCES_PREFIX "${QmlDesignerDir}/designercore"
CONDITION TARGET qmldomlib
DEPENDS qmldomlib
SOURCES SOURCES
projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h
projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h
) )
endif()

View File

@@ -582,12 +582,22 @@ const char *isQualifiedToString(IsQualified isQualified)
const char *importKindToText(ImportKind kind) const char *importKindToText(ImportKind kind)
{ {
switch (kind) { switch (kind) {
case ImportKind::Module: case ImportKind::Import:
return "Module"; return "Import";
case ImportKind::Directory: case ImportKind::ModuleDependency:
return "Directory"; return "ModuleDependency";
case ImportKind::QmlTypesDependency: }
return "QmlTypesDependency";
return "";
}
const char *isAutoVersionToText(IsAutoVersion isAutoVersion)
{
switch (isAutoVersion) {
case IsAutoVersion::No:
return "is not autoversion";
case IsAutoVersion::Yes:
return "is auto version";
} }
return ""; return "";
@@ -671,11 +681,6 @@ std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType)
<< exportedType.version << ")"; << exportedType.version << ")";
} }
std::ostream &operator<<(std::ostream &out, const NativeType &nativeType)
{
return out << "(\"" << nativeType.name << "\")";
}
std::ostream &operator<<(std::ostream &out, const ImportedType &importedType) std::ostream &operator<<(std::ostream &out, const ImportedType &importedType)
{ {
return out << "(\"" << importedType.name << "\")"; return out << "(\"" << importedType.name << "\")";
@@ -701,8 +706,8 @@ std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyD
using Utils::operator<<; using Utils::operator<<;
return out << "(\"" << propertyDeclaration.name << "\", " << propertyDeclaration.typeName return out << "(\"" << propertyDeclaration.name << "\", " << propertyDeclaration.typeName
<< ", " << propertyDeclaration.typeId << ", " << propertyDeclaration.traits << ", " << ", " << propertyDeclaration.typeId << ", " << propertyDeclaration.traits << ", "
<< propertyDeclaration.typeId << ", \"" << propertyDeclaration.aliasPropertyName << propertyDeclaration.propertyTypeId << ", \""
<< "\")"; << propertyDeclaration.aliasPropertyName << "\")";
} }
std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits) 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); 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) std::ostream &operator<<(std::ostream &out, const Import &import)
{ {
return out << "(" << import.moduleId << ", " << import.version << ", " << import.sourceId << ")"; 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 Storage
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -156,14 +156,12 @@ std::ostream &operator<<(std::ostream &out, const SourceContext &sourceContext);
namespace Storage { namespace Storage {
class Type; class Type;
class ExportedType; class ExportedType;
class NativeType;
class ImportedType; class ImportedType;
class QualifiedImportedType; class QualifiedImportedType;
using TypeName = Utils::variant<NativeType, ExportedType>;
class Version; class Version;
class VersionNumber; class VersionNumber;
enum class TypeAccessSemantics : int; enum class TypeAccessSemantics : int;
enum class PropertyDeclarationTraits : unsigned int; enum class PropertyDeclarationTraits : int;
class PropertyDeclaration; class PropertyDeclaration;
class FunctionDeclaration; class FunctionDeclaration;
class ParameterDeclaration; class ParameterDeclaration;
@@ -171,19 +169,20 @@ class SignalDeclaration;
class EnumerationDeclaration; class EnumerationDeclaration;
class EnumeratorDeclaration; class EnumeratorDeclaration;
enum class ImportKind : char; enum class ImportKind : char;
enum class IsAutoVersion : char;
class Import; class Import;
enum class IsQualified : int; enum class IsQualified : int;
class ProjectData; class ProjectData;
class SynchronizationPackage; class SynchronizationPackage;
enum class FileType : char; enum class FileType : char;
enum class ChangeLevel : char; enum class ChangeLevel : char;
class ModuleExportedImport;
std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics); std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics);
std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber); std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber);
std::ostream &operator<<(std::ostream &out, Version version); std::ostream &operator<<(std::ostream &out, Version version);
std::ostream &operator<<(std::ostream &out, const Type &type); 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 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 ImportedType &importedType);
std::ostream &operator<<(std::ostream &out, const QualifiedImportedType &importedType); std::ostream &operator<<(std::ostream &out, const QualifiedImportedType &importedType);
std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyDeclaration); 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, const SynchronizationPackage &package);
std::ostream &operator<<(std::ostream &out, FileType fileType); std::ostream &operator<<(std::ostream &out, FileType fileType);
std::ostream &operator<<(std::ostream &out, ChangeLevel changeLevel); std::ostream &operator<<(std::ostream &out, ChangeLevel changeLevel);
std::ostream &operator<<(std::ostream &out, const ModuleExportedImport &import);
} // namespace Storage } // namespace Storage

View File

@@ -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

View File

@@ -26,7 +26,6 @@
#include "googletest.h" #include "googletest.h"
#include "filesystemmock.h" #include "filesystemmock.h"
#include "projectmanagermock.h"
#include "projectstoragemock.h" #include "projectstoragemock.h"
#include "qmldocumentparsermock.h" #include "qmldocumentparsermock.h"
#include "qmltypesparsermock.h" #include "qmltypesparsermock.h"
@@ -48,6 +47,10 @@ using QmlDesigner::Storage::TypeAccessSemantics;
namespace Storage = QmlDesigner::Storage; namespace Storage = QmlDesigner::Storage;
using QmlDesigner::IdPaths; using QmlDesigner::IdPaths;
using QmlDesigner::Storage::FileType; 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::SynchronizationPackage;
using QmlDesigner::Storage::Version; using QmlDesigner::Storage::Version;
@@ -120,7 +123,7 @@ MATCHER_P4(IsProjectData,
{ {
const Storage::ProjectData &projectData = arg; 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; && 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() return package.imports.empty() && package.types.empty() && package.fileStatuses.empty()
&& package.updatedSourceIds.empty() && package.projectDatas.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 class ProjectStorageUpdater : public testing::Test
@@ -153,7 +158,6 @@ public:
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId))) ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
.WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421})); .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421}));
ON_CALL(projectManagerMock, qtQmlDirs()).WillByDefault(Return(QStringList{"/path/qmldir"}));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
.WillByDefault(Return(qmldirContent)); .WillByDefault(Return(qmldirContent));
@@ -169,8 +173,9 @@ public:
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14})); .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3))) ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 2})); .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 2}));
ON_CALL(projectStorageMock, moduleId(Eq("Example"))).WillByDefault(Return(exampleModuleId)); ON_CALL(projectStorageMock, moduleId(_)).WillByDefault([&](const auto &name) {
ON_CALL(projectStorageMock, moduleId(Eq("Qml"))).WillByDefault(Return(qmlModuleId)); return storage.moduleId(name);
});
firstType.prototype = Storage::ImportedType{"Object"}; firstType.prototype = Storage::ImportedType{"Object"};
secondType.prototype = Storage::ImportedType{"Object2"}; secondType.prototype = Storage::ImportedType{"Object2"};
@@ -178,24 +183,27 @@ public:
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
.WillByDefault(Return(qmlDocument1)); .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)); .WillByDefault(Return(qmlDocument2));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
.WillByDefault(Return(qmlDocument3)); .WillByDefault(Return(qmlDocument3));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
.WillByDefault(Return(qmltypes1)); .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)); .WillByDefault(Return(qmltypes2));
ON_CALL(qmlDocumentParserMock, parse(qmlDocument1, _)).WillByDefault([&](auto, auto &imports) { ON_CALL(qmlDocumentParserMock, parse(qmlDocument1, _, _, _))
.WillByDefault([&](auto, auto &imports, auto, auto) {
imports.push_back(import1); imports.push_back(import1);
return firstType; return firstType;
}); });
ON_CALL(qmlDocumentParserMock, parse(qmlDocument2, _)).WillByDefault([&](auto, auto &imports) { ON_CALL(qmlDocumentParserMock, parse(qmlDocument2, _, _, _))
.WillByDefault([&](auto, auto &imports, auto, auto) {
imports.push_back(import2); imports.push_back(import2);
return secondType; return secondType;
}); });
ON_CALL(qmlDocumentParserMock, parse(qmlDocument3, _)).WillByDefault([&](auto, auto &imports) { ON_CALL(qmlDocumentParserMock, parse(qmlDocument3, _, _, _))
.WillByDefault([&](auto, auto &imports, auto, auto) {
imports.push_back(import3); imports.push_back(import3);
return thirdType; return thirdType;
}); });
@@ -212,7 +220,6 @@ public:
} }
protected: protected:
NiceMock<ProjectManagerMock> projectManagerMock;
NiceMock<FileSystemMock> fileSystemMock; NiceMock<FileSystemMock> fileSystemMock;
NiceMock<ProjectStorageMock> projectStorageMock; NiceMock<ProjectStorageMock> projectStorageMock;
NiceMock<QmlTypesParserMock> qmlTypesParserMock; NiceMock<QmlTypesParserMock> qmlTypesParserMock;
@@ -222,29 +229,36 @@ protected:
QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()}; QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{ QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
storage}; storage};
QmlDesigner::ProjectUpdater updater{projectManagerMock, QmlDesigner::ProjectStorageUpdater updater{fileSystemMock,
fileSystemMock,
projectStorageMock, projectStorageMock,
fileStatusCache, fileStatusCache,
sourcePathCache, sourcePathCache,
qmlDocumentParserMock, qmlDocumentParserMock,
qmlTypesParserMock}; qmlTypesParserMock};
SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); 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 qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
SourceId qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml"); 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"); SourceId qmlDocumentSourceId3 = sourcePathCache.sourceId("/path/Second.qml");
ModuleId qmlModuleId{storage.moduleId("Qml")}; ModuleId qmlModuleId{storage.moduleId("Qml")};
ModuleId qmlCppNativeModuleId{storage.moduleId("Qml-cppnative")};
ModuleId exampleModuleId{storage.moduleId("Example")}; 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::Type objectType{"QObject",
Storage::NativeType{}, Storage::ImportedType{},
Storage::TypeAccessSemantics::Reference, Storage::TypeAccessSemantics::Reference,
qmltypesPathSourceId, qmltypesPathSourceId,
{Storage::ExportedType{exampleModuleId, "Object"}, {Storage::ExportedType{exampleModuleId, "Object"},
Storage::ExportedType{exampleModuleId, "Obj"}}}; Storage::ExportedType{exampleModuleId, "Obj"}}};
Storage::Type itemType{"QItem", Storage::Type itemType{"QItem",
Storage::NativeType{}, Storage::ImportedType{},
Storage::TypeAccessSemantics::Reference, Storage::TypeAccessSemantics::Reference,
qmltypes2PathSourceId, qmltypes2PathSourceId,
{Storage::ExportedType{exampleModuleId, "Item"}}}; {Storage::ExportedType{exampleModuleId, "Item"}}};
@@ -262,6 +276,7 @@ protected:
QString qmldirContent{"module Example\ntypeinfo example.qmltypes\n"}; QString qmldirContent{"module Example\ntypeinfo example.qmltypes\n"};
QString qmltypes1{"Module {\ndependencies: [module1]}"}; QString qmltypes1{"Module {\ndependencies: [module1]}"};
QString qmltypes2{"Module {\ndependencies: [module2]}"}; QString qmltypes2{"Module {\ndependencies: [module2]}"};
QStringList qmlDirs = {"/path/qmldir"};
}; };
TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent) TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
@@ -269,9 +284,7 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
SourceId qmlDir1PathSourceId = sourcePathCache.sourceId("/path/one/qmldir"); SourceId qmlDir1PathSourceId = sourcePathCache.sourceId("/path/one/qmldir");
SourceId qmlDir2PathSourceId = sourcePathCache.sourceId("/path/two/qmldir"); SourceId qmlDir2PathSourceId = sourcePathCache.sourceId("/path/two/qmldir");
SourceId qmlDir3PathSourceId = sourcePathCache.sourceId("/path/three/qmldir"); SourceId qmlDir3PathSourceId = sourcePathCache.sourceId("/path/three/qmldir");
ON_CALL(projectManagerMock, qtQmlDirs()) QStringList qmlDirs = {"/path/one/qmldir", "/path/two/qmldir", "/path/three/qmldir"};
.WillByDefault(
Return(QStringList{"/path/one/qmldir", "/path/two/qmldir", "/path/three/qmldir"}));
ON_CALL(fileSystemMock, fileStatus(_)).WillByDefault([](auto sourceId) { ON_CALL(fileSystemMock, fileStatus(_)).WillByDefault([](auto sourceId) {
return FileStatus{sourceId, 21, 421}; 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/one/qmldir"))));
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/two/qmldir")))); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/two/qmldir"))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, RequestFileStatusFromFileSystem) TEST_F(ProjectStorageUpdater, RequestFileStatusFromFileSystem)
@@ -295,7 +308,7 @@ TEST_F(ProjectStorageUpdater, RequestFileStatusFromFileSystem)
EXPECT_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId))); EXPECT_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, GetContentForQmlTypes) TEST_F(ProjectStorageUpdater, GetContentForQmlTypes)
@@ -307,7 +320,7 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypes)
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsInvalid) TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsInvalid)
@@ -321,7 +334,7 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsI
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsInvalid) TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsInvalid)
@@ -334,26 +347,28 @@ TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsI
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))).Times(0); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))).Times(0);
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, ParseQmlTypes) TEST_F(ProjectStorageUpdater, ParseQmlTypes)
{ {
QString qmldir{R"(module Example QString qmldir{R"(module Example
typeinfo example.qmltypes typeinfo example.qmltypes
typeinfo example2.qmltypes)"}; typeinfo types/example2.qmltypes)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
QString qmltypes{"Module {\ndependencies: []}"}; QString qmltypes{"Module {\ndependencies: []}"};
QString qmltypes2{"Module {\ndependencies: [foo]}"}; QString qmltypes2{"Module {\ndependencies: [foo]}"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
.WillByDefault(Return(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)); .WillByDefault(Return(qmltypes2));
EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _)); EXPECT_CALL(qmlTypesParserMock,
EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _)); parse(qmltypes, _, _, Field(&ProjectData::moduleId, exampleCppNativeModuleId)));
EXPECT_CALL(qmlTypesParserMock,
parse(qmltypes2, _, _, Field(&ProjectData::moduleId, exampleCppNativeModuleId)));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange) TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
@@ -367,7 +382,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes) TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
@@ -383,6 +398,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
}); });
EXPECT_CALL(projectStorageMock, moduleId(Eq("Example"))); EXPECT_CALL(projectStorageMock, moduleId(Eq("Example")));
EXPECT_CALL(projectStorageMock, moduleId(Eq("Example-cppnative")));
EXPECT_CALL(projectStorageMock, moduleId(Eq("/path")));
EXPECT_CALL(projectStorageMock, EXPECT_CALL(projectStorageMock,
synchronize( synchronize(
AllOf(Field(&SynchronizationPackage::imports, ElementsAre(import)), AllOf(Field(&SynchronizationPackage::imports, ElementsAre(import)),
@@ -395,12 +412,12 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
Field(&SynchronizationPackage::projectDatas, Field(&SynchronizationPackage::projectDatas,
UnorderedElementsAre(IsProjectData(qmlDirPathSourceId, UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
qmltypesPathSourceId, qmltypesPathSourceId,
exampleModuleId, exampleCppNativeModuleId,
FileType::QmlTypes))), FileType::QmlTypes))),
Field(&SynchronizationPackage::updatedProjectSourceIds, Field(&SynchronizationPackage::updatedProjectSourceIds,
UnorderedElementsAre(qmlDirPathSourceId))))); UnorderedElementsAre(qmlDirPathSourceId)))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged) TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
@@ -419,28 +436,37 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, GetContentForQmlDocuments) TEST_F(ProjectStorageUpdater, GetContentForQmlDocuments)
{ {
QString qmldir{"module Example\nFirstType 1.0 First.qml\nFirstTypeV2 2.2 " SourceId oldSecondSourceId3 = sourcePathCache.sourceId("/path/OldSecond.qml");
"First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"}; 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")))) EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
.WillRepeatedly(Return(qmldir)); .WillRepeatedly(Return(qmldir));
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml")))); 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")))); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, ParseQmlDocuments) TEST_F(ProjectStorageUpdater, ParseQmlDocuments)
{ {
QString qmldir{R"(module Example QString qmldir{R"(module Example
FirstType 1.0 First.qml FirstType 1.0 First.qml
FirstTypeV2 2.2 First.2.qml FirstTypeV2 2.2 First2.qml
SecondType 2.2 Second.qml)"}; SecondType 2.2 Second.qml)"};
QString qmlDocument1{"First{}"}; QString qmlDocument1{"First{}"};
QString qmlDocument2{"Second{}"}; 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/qmldir")))).WillByDefault(Return(qmldir));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
.WillByDefault(Return(qmlDocument1)); .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)); .WillByDefault(Return(qmlDocument2));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
.WillByDefault(Return(qmlDocument3)); .WillByDefault(Return(qmlDocument3));
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument1, _)); EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument1, _, _, _));
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument2, _)); EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument2, _, _, _));
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument3, _)); EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument3, _, _, _));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, ParseQmlDocumentsWithNonExistingQmlDocumentThrows) TEST_F(ProjectStorageUpdater, ParseQmlDocumentsWithNonExistingQmlDocumentThrows)
@@ -466,14 +492,14 @@ TEST_F(ProjectStorageUpdater, ParseQmlDocumentsWithNonExistingQmlDocumentThrows)
NonexitingType 1.0 NonexitingType.qml)"}; NonexitingType 1.0 NonexitingType.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); 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) TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
{ {
QString qmldir{R"(module Example QString qmldir{R"(module Example
FirstType 1.0 First.qml FirstType 1.0 First.qml
FirstType 2.2 First.2.qml FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"}; SecondType 2.2 Second.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
@@ -489,21 +515,24 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
qmlDocumentSourceId1, qmlDocumentSourceId1,
Storage::ChangeLevel::Full), Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
AllOf(IsStorageType("First.2.qml", IsExportedType(pathModuleId, "First", -1, -1)))),
AllOf(IsStorageType("First2.qml",
Storage::ImportedType{"Object2"}, Storage::ImportedType{"Object2"},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
qmlDocumentSourceId2, qmlDocumentSourceId2,
Storage::ChangeLevel::Full), Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes, 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", AllOf(IsStorageType("Second.qml",
Storage::ImportedType{"Object3"}, Storage::ImportedType{"Object3"},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
qmlDocumentSourceId3, qmlDocumentSourceId3,
Storage::ChangeLevel::Full), Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2)))))), ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
IsExportedType(pathModuleId, "Second", -1, -1)))))),
Field(&SynchronizationPackage::updatedSourceIds, Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, UnorderedElementsAre(qmlDirPathSourceId,
qmlDocumentSourceId1, qmlDocumentSourceId1,
@@ -535,16 +564,16 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
exampleModuleId, exampleModuleId,
FileType::QmlDocument)))))); FileType::QmlDocument))))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, SynchronizeRemoved) TEST_F(ProjectStorageUpdater, SynchronizeRemoved)
{ {
QString qmldir{R"(module Example QString qmldir{R"(module Example
FirstType 1.0 First.qml FirstType 1.0 First.qml
FirstType 2.2 First.2.qml FirstType 2.2 First2.qml
typeinfo example.qmltypes typeinfo example.qmltypes
typeinfo example2.qmltypes typeinfo types/example2.qmltypes
)"}; )"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2))) ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2)))
@@ -572,14 +601,16 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemoved)
qmlDocumentSourceId1, qmlDocumentSourceId1,
Storage::ChangeLevel::Full), Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
AllOf(IsStorageType("First.2.qml", IsExportedType(pathModuleId, "First", -1, -1)))),
Storage::NativeType{}, AllOf(IsStorageType("First2.qml",
Storage::ImportedType{},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
qmlDocumentSourceId2, qmlDocumentSourceId2,
Storage::ChangeLevel::Minimal), Storage::ChangeLevel::Minimal),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))))), ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
IsExportedType(pathModuleId, "First2", -1, -1)))))),
Field(&SynchronizationPackage::updatedSourceIds, Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, UnorderedElementsAre(qmlDirPathSourceId,
qmltypesPathSourceId, qmltypesPathSourceId,
@@ -608,21 +639,21 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemoved)
FileType::QmlDocument), FileType::QmlDocument),
IsProjectData(qmlDirPathSourceId, IsProjectData(qmlDirPathSourceId,
qmltypesPathSourceId, qmltypesPathSourceId,
exampleModuleId, exampleCppNativeModuleId,
FileType::QmlTypes), FileType::QmlTypes),
IsProjectData(qmlDirPathSourceId, IsProjectData(qmlDirPathSourceId,
qmltypes2PathSourceId, qmltypes2PathSourceId,
exampleModuleId, exampleCppNativeModuleId,
FileType::QmlTypes)))))); FileType::QmlTypes))))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate) TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
{ {
QString qmldir{R"(module Example QString qmldir{R"(module Example
FirstType 1.0 First.qml FirstType 1.0 First.qml
FirstType 2.2 First.2.qml FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"}; SecondType 2.2 Second.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3))) ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
@@ -640,21 +671,24 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
qmlDocumentSourceId1, qmlDocumentSourceId1,
Storage::ChangeLevel::Full), Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))), ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
AllOf(IsStorageType("First.2.qml", IsExportedType(pathModuleId, "First", -1, -1)))),
AllOf(IsStorageType("First2.qml",
Storage::ImportedType{"Object2"}, Storage::ImportedType{"Object2"},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
qmlDocumentSourceId2, qmlDocumentSourceId2,
Storage::ChangeLevel::Full), Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes, 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", AllOf(IsStorageType("Second.qml",
Storage::NativeType{}, Storage::ImportedType{},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
qmlDocumentSourceId3, qmlDocumentSourceId3,
Storage::ChangeLevel::Minimal), Storage::ChangeLevel::Minimal),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2)))))), ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
IsExportedType(pathModuleId, "Second", -1, -1)))))),
Field(&SynchronizationPackage::updatedSourceIds, Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, UnorderedElementsAre(qmlDirPathSourceId,
qmlDocumentSourceId1, qmlDocumentSourceId1,
@@ -682,14 +716,14 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
exampleModuleId, exampleModuleId,
FileType::QmlDocument)))))); FileType::QmlDocument))))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments) TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments)
{ {
QString qmldir{R"(module Example QString qmldir{R"(module Example
FirstType 1.1 First.qml FirstType 1.1 First.qml
FirstType 2.2 First.2.qml FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"}; SecondType 2.2 Second.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3))) ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
@@ -716,7 +750,7 @@ TEST_F(ProjectStorageUpdater, AddSourceIdForForInvalidQmldirFileStatus)
Field(&SynchronizationPackage::fileStatuses, IsEmpty()), Field(&SynchronizationPackage::fileStatuses, IsEmpty()),
Field(&SynchronizationPackage::updatedFileStatusSourceIds, IsEmpty()), Field(&SynchronizationPackage::updatedFileStatusSourceIds, IsEmpty()),
Field(&SynchronizationPackage::projectDatas, IsEmpty())))); Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged) TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
@@ -744,7 +778,7 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
qmlDocumentSourceId1, qmlDocumentSourceId1,
Storage::ChangeLevel::ExcludeExportedTypes), Storage::ChangeLevel::ExcludeExportedTypes),
Field(&Storage::Type::exportedTypes, IsEmpty())), Field(&Storage::Type::exportedTypes, IsEmpty())),
AllOf(IsStorageType("First.2.qml", AllOf(IsStorageType("First2.qml",
Storage::ImportedType{"Object2"}, Storage::ImportedType{"Object2"},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
qmlDocumentSourceId2, qmlDocumentSourceId2,
@@ -767,7 +801,7 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
qmlDocumentSourceId2)), qmlDocumentSourceId2)),
Field(&SynchronizationPackage::projectDatas, IsEmpty())))); Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
updater.update(); updater.update(qmlDirs, {});
} }
TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedFiles) TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedFiles)
@@ -806,7 +840,464 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedF
UnorderedElementsAre(qmltypesPathSourceId, qmlDocumentSourceId1)), UnorderedElementsAre(qmltypesPathSourceId, qmlDocumentSourceId1)),
Field(&SynchronizationPackage::projectDatas, IsEmpty())))); 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 } // namespace

View File

@@ -59,6 +59,41 @@ MATCHER_P3(IsPropertyDeclaration,
&& propertyDeclaration.traits == traits; && 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, MATCHER_P2(IsFunctionDeclaration,
name, name,
returnTypeName, returnTypeName,
@@ -129,12 +164,12 @@ protected:
QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()}; QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{ QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
storage}; storage};
QmlDesigner::QmlDocumentParser parser{storage}; QmlDesigner::QmlDocumentParser parser{storage, sourcePathCache};
Storage::Imports imports; Storage::Imports imports;
SourceId qmlFileSourceId{sourcePathCache.sourceId("path/to/qmlfile.qml")}; SourceId qmlFileSourceId{sourcePathCache.sourceId("/path/to/qmlfile.qml")};
SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)}; SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)};
QString directoryPath{"/path/to"}; Utils::PathString directoryPath{sourcePathCache.sourceContextPath(qmlFileSourceContextId)};
ModuleId directoryModuleId{storage.moduleId("/path/to")}; ModuleId directoryModuleId{storage.moduleId(directoryPath)};
}; };
TEST_F(QmlDocumentParser, Prototype) TEST_F(QmlDocumentParser, Prototype)
@@ -144,22 +179,24 @@ TEST_F(QmlDocumentParser, Prototype)
ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example"))); ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example")));
} }
TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype) TEST_F(QmlDocumentParser, QualifiedPrototype)
{ {
auto exampleModuleId = storage.moduleId("Example"); auto exampleModuleId = storage.moduleId("Example");
auto type = parser.parse("import Example as Example\n Example.Item{}", QString text = R"(import Example 2.1 as Example
imports, Example.Item{})";
qmlFileSourceId,
directoryPath); auto type = parser.parse(text, imports, qmlFileSourceId, directoryPath);
ASSERT_THAT(type, ASSERT_THAT(type,
HasPrototype(Storage::QualifiedImportedType( HasPrototype(Storage::QualifiedImportedType("Item",
"Item", Storage::Import{exampleModuleId, Storage::Version{}, qmlFileSourceId}))); Storage::Import{exampleModuleId,
Storage::Version{2, 1},
qmlFileSourceId})));
} }
TEST_F(QmlDocumentParser, Properties) 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, ASSERT_THAT(type.propertyDeclarations,
UnorderedElementsAre(IsPropertyDeclaration("foo", UnorderedElementsAre(IsPropertyDeclaration("foo",
@@ -167,12 +204,66 @@ TEST_F(QmlDocumentParser, Properties)
Storage::PropertyDeclarationTraits::None))); 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) TEST_F(QmlDocumentParser, Imports)
{ {
ModuleId fooDirectoryModuleId = storage.moduleId("/path/foo"); ModuleId fooDirectoryModuleId = storage.moduleId("/path/foo");
ModuleId qmlModuleId = storage.moduleId("QML"); ModuleId qmlModuleId = storage.moduleId("QML");
ModuleId qtQmlModuleId = storage.moduleId("QtQml");
ModuleId qtQuickModuleId = storage.moduleId("QtQuick"); ModuleId qtQuickModuleId = storage.moduleId("QtQuick");
auto type = parser.parse(R"(import QtQuick auto type = parser.parse(R"(import QtQuick
import "../foo" import "../foo"
Example{})", Example{})",
@@ -184,8 +275,48 @@ TEST_F(QmlDocumentParser, Imports)
UnorderedElementsAre( UnorderedElementsAre(
Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId}, Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId}, Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId},
Storage::Import{qmlModuleId, Storage::Version{1, 0}, qmlFileSourceId}, Storage::Import{qmlModuleId, Storage::Version{}, qmlFileSourceId},
Storage::Import{qtQmlModuleId, Storage::Version{6, 0}, 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})); Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
} }
@@ -243,4 +374,162 @@ TEST_F(QmlDocumentParser, Enumeration)
ElementsAre(IsEnumerator("On", 0), IsEnumerator("Off", 1)))))); 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 } // namespace

View File

@@ -34,6 +34,9 @@ class QmlDocumentParserMock : public QmlDesigner::QmlDocumentParserInterface
public: public:
MOCK_METHOD(QmlDesigner::Storage::Type, MOCK_METHOD(QmlDesigner::Storage::Type,
parse, parse,
(const QString &, QmlDesigner::Storage::Imports &), (const QString &sourceContent,
QmlDesigner::Storage::Imports &imports,
QmlDesigner::SourceId sourceId,
Utils::SmallStringView directoryPath),
(override)); (override));
}; };

View File

@@ -173,9 +173,10 @@ protected:
Storage::Imports imports; Storage::Imports imports;
Storage::Types types; Storage::Types types;
SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")}; SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")};
ModuleId qtQmlNativeModuleId = storage.moduleId("QtQml-cppnative");
QmlDesigner::Storage::ProjectData projectData{qmltypesFileSourceId, QmlDesigner::Storage::ProjectData projectData{qmltypesFileSourceId,
qmltypesFileSourceId, qmltypesFileSourceId,
storage.moduleId("QtQml-cppnative"), qtQmlNativeModuleId,
Storage::FileType::QmlTypes}; Storage::FileType::QmlTypes};
SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)}; SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)};
ModuleId directoryModuleId{storage.moduleId("path/to/")}; ModuleId directoryModuleId{storage.moduleId("path/to/")};
@@ -193,13 +194,11 @@ TEST_F(QmlTypesParser, Imports)
ASSERT_THAT( ASSERT_THAT(
imports, imports,
UnorderedElementsAre( 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("QtQml-cppnative"), Storage::Version{}, qmltypesFileSourceId),
IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{2, 15}, qmltypesFileSourceId), IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{}, qmltypesFileSourceId),
IsImport(storage.moduleId("QtQuick.Window-cppnative"), IsImport(storage.moduleId("QtQuick.Window-cppnative"), Storage::Version{}, qmltypesFileSourceId),
Storage::Version{2, 1}, IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{}, qmltypesFileSourceId)));
qmltypesFileSourceId),
IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{6}, qmltypesFileSourceId)));
} }
TEST_F(QmlTypesParser, Types) TEST_F(QmlTypesParser, Types)
@@ -214,11 +213,11 @@ TEST_F(QmlTypesParser, Types)
ASSERT_THAT(types, ASSERT_THAT(types,
UnorderedElementsAre(IsType("QObject", UnorderedElementsAre(IsType("QObject",
Storage::NativeType{}, Storage::ImportedType{},
Storage::TypeAccessSemantics::Reference, Storage::TypeAccessSemantics::Reference,
qmltypesFileSourceId), qmltypesFileSourceId),
IsType("QQmlComponent", IsType("QQmlComponent",
Storage::NativeType{"QObject"}, Storage::ImportedType{"QObject"},
Storage::TypeAccessSemantics::Reference, Storage::TypeAccessSemantics::Reference,
qmltypesFileSourceId))); qmltypesFileSourceId)));
} }
@@ -232,14 +231,14 @@ TEST_F(QmlTypesParser, ExportedTypes)
}})"}; }})"};
ModuleId qmlModuleId = storage.moduleId("QML"); ModuleId qmlModuleId = storage.moduleId("QML");
ModuleId qtQmlModuleId = storage.moduleId("QtQml"); ModuleId qtQmlModuleId = storage.moduleId("QtQml");
ModuleId qtQmlNativeModuleId = storage.moduleId("QtQml-cppnative");
parser.parse(source, imports, types, projectData); parser.parse(source, imports, types, projectData);
ASSERT_THAT(types, ASSERT_THAT(types,
ElementsAre(Field( ElementsAre(
&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(qmlModuleId, "QtObject", Storage::Version{1, 0}), UnorderedElementsAre(
IsExportedType(qmlModuleId, "QtObject", Storage::Version{1, 0}),
IsExportedType(qtQmlModuleId, "QtObject", Storage::Version{2, 1}), IsExportedType(qtQmlModuleId, "QtObject", Storage::Version{2, 1}),
IsExportedType(qtQmlNativeModuleId, "QObject", Storage::Version{}))))); IsExportedType(qtQmlNativeModuleId, "QObject", Storage::Version{})))));
} }
@@ -262,21 +261,69 @@ TEST_F(QmlTypesParser, Properties)
&Storage::Type::propertyDeclarations, &Storage::Type::propertyDeclarations,
UnorderedElementsAre( UnorderedElementsAre(
IsPropertyDeclaration("objectName", IsPropertyDeclaration("objectName",
Storage::NativeType{"string"}, Storage::ImportedType{"string"},
Storage::PropertyDeclarationTraits::None), Storage::PropertyDeclarationTraits::None),
IsPropertyDeclaration("target", IsPropertyDeclaration("target",
Storage::NativeType{"QObject"}, Storage::ImportedType{"QObject"},
Storage::PropertyDeclarationTraits::IsPointer), Storage::PropertyDeclarationTraits::IsPointer),
IsPropertyDeclaration("progress", IsPropertyDeclaration("progress",
Storage::NativeType{"double"}, Storage::ImportedType{"double"},
Storage::PropertyDeclarationTraits::IsReadOnly), Storage::PropertyDeclarationTraits::IsReadOnly),
IsPropertyDeclaration("targets", IsPropertyDeclaration("targets",
Storage::NativeType{"QQuickItem"}, Storage::ImportedType{"QQuickItem"},
Storage::PropertyDeclarationTraits::IsReadOnly Storage::PropertyDeclarationTraits::IsReadOnly
| Storage::PropertyDeclarationTraits::IsList | Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsPointer))))); | 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) TEST_F(QmlTypesParser, Functions)
{ {
QString source{R"(import QtQuick.tooling 1.2 QString source{R"(import QtQuick.tooling 1.2
@@ -319,6 +366,50 @@ TEST_F(QmlTypesParser, Functions)
Field(&Storage::FunctionDeclaration::parameters, IsEmpty())))))); 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) TEST_F(QmlTypesParser, Signals)
{ {
QString source{R"(import QtQuick.tooling 1.2 QString source{R"(import QtQuick.tooling 1.2
@@ -358,6 +449,34 @@ TEST_F(QmlTypesParser, Signals)
IsParameter("args", "QQmlV4Function")))))))); 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) TEST_F(QmlTypesParser, Enumerations)
{ {
QString source{R"(import QtQuick.tooling 1.2 QString source{R"(import QtQuick.tooling 1.2
@@ -381,7 +500,7 @@ TEST_F(QmlTypesParser, Enumerations)
parser.parse(source, imports, types, projectData); parser.parse(source, imports, types, projectData);
ASSERT_THAT(types, ASSERT_THAT(types,
ElementsAre( Contains(
Field(&Storage::Type::enumerationDeclarations, Field(&Storage::Type::enumerationDeclarations,
UnorderedElementsAre( UnorderedElementsAre(
AllOf(IsEnumeration("NamedColorSpace"), AllOf(IsEnumeration("NamedColorSpace"),
@@ -396,4 +515,185 @@ TEST_F(QmlTypesParser, Enumerations)
IsEnumerator("BottomToTop")))))))); 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 } // namespace