aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2017-06-15 08:57:58 +0200
committerLiang Qi <liang.qi@qt.io>2017-06-15 09:10:12 +0200
commit9f3aefb086c5f9d6b9dd192689bdd473da07186a (patch)
tree93349812f4a46305edf5e27f7e737d952e0d9a3a /src
parenta021bd87755ccfbe49e132f942ded935c9719b00 (diff)
parentd2bb2e202427ebae545a408f065c893f3d837061 (diff)
Merge remote-tracking branch 'origin/5.9' into dev
Conflicts: src/qml/compiler/qv4codegen.cpp Change-Id: I3c41b9fc9ba7d41741e4dd400402ae80dd7726d9
Diffstat (limited to 'src')
-rw-r--r--src/imports/testlib/TestCase.qml4
-rw-r--r--src/qml/compiler/compiler.pri4
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp3
-rw-r--r--src/qml/compiler/qv4codegen.cpp172
-rw-r--r--src/qml/compiler/qv4codegen_p.h12
-rw-r--r--src/qml/compiler/qv4compileddata.cpp2
-rw-r--r--src/qml/compiler/qv4jsir_p.h18
-rw-r--r--src/qml/compiler/qv4ssa.cpp6
-rw-r--r--src/qml/compiler/qv4ssa_p.h2
-rw-r--r--src/qml/doc/images/cppintegration-ex.pngbin0 -> 1777 bytes
-rw-r--r--src/qml/doc/snippets/code/backend/backend.cpp70
-rw-r--r--src/qml/doc/snippets/code/backend/backend.h75
-rw-r--r--src/qml/doc/snippets/code/backend/main.cpp66
-rw-r--r--src/qml/doc/snippets/code/backend/main.qml79
-rw-r--r--src/qml/doc/src/cppintegration/topic.qdoc63
-rw-r--r--src/qml/jit/qv4unop.cpp9
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp4
-rw-r--r--src/qml/qml/qqmlengine.cpp2
-rw-r--r--src/qml/qml/qqmlfile.cpp6
-rw-r--r--src/qmltest/quicktestresult.cpp6
-rw-r--r--src/quick/doc/snippets/qml/regexp.qml46
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc59
-rw-r--r--src/quick/doc/src/concepts/positioning/layouts.qdoc3
-rw-r--r--src/quick/items/qquickgridview.cpp4
-rw-r--r--src/quick/items/qquickitemview.cpp8
-rw-r--r--src/quick/items/qquickitemview_p_p.h9
-rw-r--r--src/quick/items/qquicklistview.cpp4
-rw-r--r--src/quick/items/qquickrepeater.cpp6
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp4
-rw-r--r--src/quick/util/qquickvalidator.cpp13
30 files changed, 667 insertions, 92 deletions
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index dbed896c59..7ff51bb6d6 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -757,6 +757,10 @@ Item {
bProperties.push(i); // collect exp's properties
}
+ if (aProperties.length == 0 && bProperties.length == 0) { // at least a special case for QUrl
+ return eq && (JSON.stringify(act) == JSON.stringify(exp));
+ }
+
// Ensures identical properties name
return eq && qtest_compareInternal(aProperties.sort(), bProperties.sort());
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 60f548a2b0..d9b985e33b 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -52,3 +52,7 @@ qmldevtools_build|qtConfig(qml-interpreter) {
$$PWD/qv4instr_moth.cpp \
$$PWD/qv4isel_moth.cpp
}
+
+gcc {
+ equals(QT_GCC_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -fno-strict-aliasing
+}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index f766f0e4c8..d8cd31de29 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1985,7 +1985,8 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
QQmlTypeNameCache::Result r = imports->query(name);
if (r.isValid()) {
if (r.scriptIndex != -1) {
- return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(QV4::IR::SInt32Type, r.scriptIndex));
+ return _block->SUBSCRIPT(_block->TEMP(_importedScriptsTemp),
+ _block->CONST(QV4::IR::SInt32Type, r.scriptIndex));
} else if (r.type) {
QV4::IR::Name *typeName = _block->NAME(name, line, col);
// Make sure the run-time loads this through the more efficient singleton getter.
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 693a4230ba..5b7a7f9050 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -113,6 +113,18 @@ static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body,
}
}
+static inline bool isSimpleExpr(IR::Expr *e)
+{
+ switch (e->exprKind) {
+ case IR::Expr::TempExpr:
+ case IR::Expr::ArgLocalExpr:
+ case IR::Expr::ConstExpr:
+ return true;
+ default:
+ return false;
+ }
+}
+
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
@@ -573,28 +585,6 @@ IR::Expr *Codegen::member(IR::Expr *base, const QString *name)
}
}
-IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index)
-{
- if (hasError)
- return 0;
-
- if (! base->asTemp() && !base->asArgLocal()) {
- const unsigned t = _block->newTemp();
- move(_block->TEMP(t), base);
- base = _block->TEMP(t);
- }
-
- if (! index->asTemp() && !index->asArgLocal() && !index->asConst()) {
- const unsigned t = _block->newTemp();
- move(_block->TEMP(t), index);
- index = _block->TEMP(t);
- }
-
- Q_ASSERT(base->asTemp() || base->asArgLocal());
- Q_ASSERT(index->asTemp() || index->asArgLocal() || index->asConst());
- return _block->SUBSCRIPT(base, index);
-}
-
IR::Expr *Codegen::argument(IR::Expr *expr)
{
if (expr && !expr->asTemp()) {
@@ -647,12 +637,14 @@ IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr, const SourceLocation &loc)
}
}
}
- if (!expr->asTemp() && !expr->asArgLocal()) {
- const unsigned t = _block->newTemp();
- setLocation(move(_block->TEMP(t), expr), loc);
- expr = _block->TEMP(t);
- }
- Q_ASSERT(expr->asTemp() || expr->asArgLocal());
+
+ TempScope scope(_function);
+ if (isSimpleExpr(expr))
+ return _block->UNOP(op, expr);
+
+ const unsigned t = _block->newTemp();
+ setLocation(move(_block->TEMP(t), expr), loc);
+ expr = _block->TEMP(t);
return _block->UNOP(op, expr);
}
@@ -661,6 +653,8 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS
if (hasError)
return 0;
+ TempScope scope(_function);
+
if (IR::Const *c1 = left->asConst()) {
if (IR::Const *c2 = right->asConst()) {
if ((c1->type & IR::NumberType) && (c2->type & IR::NumberType)) {
@@ -748,6 +742,8 @@ IR::Stmt *Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op)
return move(target, binop(op, target, source));
}
+ TempScope scope(_function);
+
if (!source->asTemp() && !source->asConst() && !target->asTemp() && !source->asArgLocal() && !target->asArgLocal()) {
unsigned t = _block->newTemp();
_block->MOVE(_block->TEMP(t), source);
@@ -767,6 +763,8 @@ IR::Stmt *Codegen::cjump(IR::Expr *cond, IR::BasicBlock *iftrue, IR::BasicBlock
if (hasError)
return 0;
+ TempScope scope(_function);
+
if (! (cond->asTemp() || (cond->asBinop() && cjumpCanHandle(cond->asBinop()->op)) )) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), cond);
@@ -786,12 +784,16 @@ void Codegen::accept(Node *node)
void Codegen::statement(Statement *ast)
{
+ TempScope scope(_function);
+
_block->nextLocation = ast->firstSourceLocation();
accept(ast);
}
void Codegen::statement(ExpressionNode *ast)
{
+ TempScope scope(_function);
+
if (! ast) {
return;
} else {
@@ -900,6 +902,7 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
if (lhs->asArgLocal()) {
move(lhs, initializer);
} else {
+ TempScope scope(_function);
int initialized = _block->newTemp();
move(_block->TEMP(initialized), initializer);
move(lhs, _block->TEMP(initialized));
@@ -1103,6 +1106,10 @@ bool Codegen::visit(ArrayLiteral *ast)
if (hasError)
return false;
+ const unsigned t = _block->newTemp();
+
+ TempScope scope(_function);
+
IR::ExprList *args = 0;
IR::ExprList *current = 0;
for (ElementList *it = ast->elements; it; it = it->next) {
@@ -1148,7 +1155,6 @@ bool Codegen::visit(ArrayLiteral *ast)
current->expr = _block->CONST(IR::MissingType, 0);
}
- const unsigned t = _block->newTemp();
move(_block->TEMP(t), _block->CALL(_block->NAME(IR::Name::builtin_define_array, 0, 0), args));
_expr.code = _block->TEMP(t);
return false;
@@ -1159,11 +1165,25 @@ bool Codegen::visit(ArrayMemberExpression *ast)
if (hasError)
return false;
- Result base = expression(ast->base);
- Result index = expression(ast->expression);
+ IR::Expr *base = *expression(ast->base);
+ if (hasError)
+ return false;
+ if (!isSimpleExpr(base)) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), base);
+ base = _block->TEMP(t);
+ }
+
+ IR::Expr *index = *expression(ast->expression);
if (hasError)
return false;
- _expr.code = subscript(*base, *index);
+ if (!isSimpleExpr(index)) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), index);
+ index = _block->TEMP(t);
+ }
+
+ _expr.code = _block->SUBSCRIPT(base, index);
return false;
}
@@ -1299,14 +1319,12 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
}
- if (_expr.accept(nx)) {
- move(left, *right, baseOp(ast->op));
- } else {
- const unsigned t = _block->newTemp();
- move(_block->TEMP(t), *right);
- move(left, _block->TEMP(t), baseOp(ast->op));
+ TempScope scope(_function);
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), *right);
+ move(left, _block->TEMP(t), baseOp(ast->op));
+ if (!_expr.accept(nx))
_expr.code = left;
- }
break;
}
@@ -1320,6 +1338,7 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::Lt:
case QSOperator::StrictEqual:
case QSOperator::StrictNotEqual: {
+ TempScope scope(_function);
if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), left), ast->operatorToken);
@@ -1349,6 +1368,7 @@ bool Codegen::visit(BinaryExpression *ast)
case QSOperator::RShift:
case QSOperator::Sub:
case QSOperator::URShift: {
+ TempScope scope(_function);
if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), left), ast->operatorToken);
@@ -1400,6 +1420,7 @@ bool Codegen::visit(ConditionalExpression *ast)
IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler());
const unsigned t = _block->newTemp();
+ TempScope scope(_function);
condition(ast->expression, iftrue, iffalse);
@@ -1503,6 +1524,8 @@ bool Codegen::visit(FunctionExpression *ast)
if (hasError)
return false;
+ TempScope scope(_function);
+
int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
_expr.code = _block->CLOSURE(function);
return false;
@@ -1583,6 +1606,7 @@ bool Codegen::visit(NewExpression *ast)
{
if (hasError)
return false;
+ TempScope scope(_function);
Result base = expression(ast->expression);
if (hasError)
@@ -1602,6 +1626,10 @@ bool Codegen::visit(NewMemberExpression *ast)
if (hasError)
return false;
+ const unsigned t = _block->newTemp();
+
+ TempScope scope(_function);
+
Result base = expression(ast->base);
if (hasError)
return false;
@@ -1622,7 +1650,6 @@ bool Codegen::visit(NewMemberExpression *ast)
(*args_it)->init(actual);
args_it = &(*args_it)->next;
}
- const unsigned t = _block->newTemp();
move(_block->TEMP(t), _block->NEW(expr, args));
_expr.code = _block->TEMP(t);
return false;
@@ -1633,10 +1660,12 @@ bool Codegen::visit(NotExpression *ast)
if (hasError)
return false;
+ const unsigned r = _block->newTemp();
+ TempScope scope(_function);
+
Result expr = expression(ast->expression);
if (hasError)
return false;
- const unsigned r = _block->newTemp();
setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken);
_expr.code = _block->TEMP(r);
return false;
@@ -1689,6 +1718,9 @@ bool Codegen::visit(ObjectLiteral *ast)
QMap<QString, ObjectPropertyValue> valueMap;
+ const unsigned t = _block->newTemp();
+ TempScope scope(_function);
+
for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
QString name = it->assignment->name->asString();
if (PropertyNameAndValue *nv = AST::cast<AST::PropertyNameAndValue *>(it->assignment)) {
@@ -1702,7 +1734,13 @@ bool Codegen::visit(ObjectLiteral *ast)
return false;
}
- valueMap[name].value = *value;
+ if (IR::Const *c = (*value)->asConst()) {
+ valueMap[name].value = c;
+ } else {
+ unsigned t = _block->newTemp();
+ move(_block->TEMP(t), *value);
+ valueMap[name].value = _block->TEMP(t);
+ }
} else if (PropertyGetterSetter *gs = AST::cast<AST::PropertyGetterSetter *>(it->assignment)) {
const int function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0);
ObjectPropertyValue &v = valueMap[name];
@@ -1773,12 +1811,9 @@ bool Codegen::visit(ObjectLiteral *ast)
current = current->next;
current->expr = _block->CONST(IR::BoolType, true);
- unsigned value = _block->newTemp();
- move(_block->TEMP(value), it->value);
-
current->next = _function->New<IR::ExprList>();
current = current->next;
- current->expr = _block->TEMP(value);
+ current->expr = it->value;
} else {
current->next = _function->New<IR::ExprList>();
current = current->next;
@@ -1811,7 +1846,6 @@ bool Codegen::visit(ObjectLiteral *ast)
args->next = arrayEntries;
}
- const unsigned t = _block->newTemp();
move(_block->TEMP(t), _block->CALL(_block->NAME(IR::Name::builtin_define_object_literal,
ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), args));
@@ -1837,6 +1871,7 @@ bool Codegen::visit(PostDecrementExpression *ast)
const unsigned oldValue = _block->newTemp();
setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->decrementToken)), ast->decrementToken);
+ TempScope scope(_function);
const unsigned newValue = _block->newTemp();
setLocation(move(_block->TEMP(newValue), binop(IR::OpSub, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->decrementToken)), ast->decrementToken);
setLocation(move(*expr, _block->TEMP(newValue)), ast->decrementToken);
@@ -1865,6 +1900,7 @@ bool Codegen::visit(PostIncrementExpression *ast)
const unsigned oldValue = _block->newTemp();
setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->incrementToken)), ast->incrementToken);
+ TempScope scope(_function);
const unsigned newValue = _block->newTemp();
setLocation(move(_block->TEMP(newValue), binop(IR::OpAdd, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->incrementToken)), ast->incrementToken);
setLocation(move(*expr, _block->TEMP(newValue)), ast->incrementToken);
@@ -1961,10 +1997,12 @@ bool Codegen::visit(TildeExpression *ast)
if (hasError)
return false;
+ const unsigned t = _block->newTemp();
+ TempScope scope(_function);
+
Result expr = expression(ast->expression);
if (hasError)
return false;
- const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken);
_expr.code = _block->TEMP(t);
return false;
@@ -1988,6 +2026,8 @@ bool Codegen::visit(TypeOfExpression *ast)
if (hasError)
return false;
+ TempScope scope(_function);
+
Result expr = expression(ast->expression);
if (hasError)
return false;
@@ -2030,6 +2070,8 @@ bool Codegen::visit(VoidExpression *ast)
if (hasError)
return false;
+ TempScope scope(_function);
+
statement(ast->expression);
_expr.code = _block->CONST(IR::UndefinedType, 0);
return false;
@@ -2040,6 +2082,8 @@ bool Codegen::visit(FunctionDeclaration * ast)
if (hasError)
return false;
+ TempScope scope(_function);
+
if (_variableEnvironment->compilationMode == QmlBinding)
move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0));
_expr.accept(nx);
@@ -2203,6 +2247,8 @@ bool Codegen::visit(Block *ast)
if (hasError)
return false;
+ TempScope scope(_function);
+
for (StatementList *it = ast->statements; it; it = it->next) {
statement(it->statement);
}
@@ -2214,6 +2260,8 @@ bool Codegen::visit(BreakStatement *ast)
if (hasError)
return false;
+ TempScope scope(_function);
+
if (!_loop) {
throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop"));
return false;
@@ -2241,6 +2289,8 @@ bool Codegen::visit(ContinueStatement *ast)
if (hasError)
return false;
+ TempScope scope(_function);
+
Loop *loop = 0;
if (ast->label.isEmpty()) {
for (loop = _loop; loop; loop = loop->parent) {
@@ -2280,6 +2330,8 @@ bool Codegen::visit(DoWhileStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
IR::BasicBlock *loopbody = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *loopcond = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *loopend = _function->newBasicBlock(exceptionHandler());
@@ -2315,6 +2367,8 @@ bool Codegen::visit(ExpressionStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
if (_variableEnvironment->compilationMode == EvalCode || _variableEnvironment->compilationMode == QmlBinding) {
Result e = expression(ast->expression);
if (*e)
@@ -2330,6 +2384,8 @@ bool Codegen::visit(ForEachStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler());
@@ -2376,6 +2432,8 @@ bool Codegen::visit(ForStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler());
@@ -2412,6 +2470,8 @@ bool Codegen::visit(IfStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(exceptionHandler()) : 0;
IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler());
@@ -2438,6 +2498,8 @@ bool Codegen::visit(LabelledStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
// check that no outer loop contains the label
Loop *l = _loop;
while (l) {
@@ -2475,6 +2537,8 @@ bool Codegen::visit(LocalForEachStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler());
@@ -2515,6 +2579,8 @@ bool Codegen::visit(LocalForStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler());
IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler());
@@ -2577,6 +2643,8 @@ bool Codegen::visit(SwitchStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
IR::BasicBlock *switchend = _function->newBasicBlock(exceptionHandler());
if (ast->block) {
@@ -2672,6 +2740,8 @@ bool Codegen::visit(ThrowStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
Result expr = expression(ast->expression);
move(_block->TEMP(_returnAddress), *expr);
IR::ExprList *throwArgs = _function->New<IR::ExprList>();
@@ -2685,6 +2755,8 @@ bool Codegen::visit(TryStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
_function->hasTry = true;
if (_function->isStrict && ast->catchExpression &&
@@ -2763,6 +2835,8 @@ bool Codegen::visit(TryStatement *ast)
_function->addBasicBlock(finallyBody);
_block = finallyBody;
+ TempScope scope(_function);
+
int hasException = _block->newTemp();
move(_block->TEMP(hasException), _block->CALL(_block->NAME(IR::Name::builtin_unwind_exception, /*line*/0, /*column*/0), 0));
@@ -2847,6 +2921,8 @@ bool Codegen::visit(WithStatement *ast)
if (hasError)
return true;
+ TempScope scope(_function);
+
_function->hasWith = true;
const int withObject = _block->newTemp();
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 239ed5c4b9..31e9cc0f46 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -249,6 +249,17 @@ protected:
}
};
+ struct TempScope {
+ TempScope(QV4::IR::Function *f)
+ : function(f),
+ tempCountForScope(f->currentTemp) {}
+ ~TempScope() {
+ function->currentTemp = tempCountForScope;
+ }
+ QV4::IR::Function *function;
+ int tempCountForScope;
+ };
+
Environment *newEnvironment(AST::Node *node, Environment *parent, CompilationMode compilationMode)
{
Environment *env = new Environment(parent, compilationMode);
@@ -311,7 +322,6 @@ protected:
}
QV4::IR::Expr *member(QV4::IR::Expr *base, const QString *name);
- QV4::IR::Expr *subscript(QV4::IR::Expr *base, QV4::IR::Expr *index);
QV4::IR::Expr *argument(QV4::IR::Expr *expr);
QV4::IR::Expr *reference(QV4::IR::Expr *expr);
QV4::IR::Expr *unop(QV4::IR::AluOp op, QV4::IR::Expr *expr, const AST::SourceLocation &loc = AST::SourceLocation());
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index a0dd4c426c..68063c2f71 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -82,7 +82,7 @@ static QString cacheFilePath(const QUrl &url)
{
const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
const QString localCachePath = localSourcePath + QLatin1Char('c');
- if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
+ if (QFile::exists(localCachePath) || QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
return localCachePath;
QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
fileNameHash.addData(localSourcePath.toUtf8());
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index b534eaa54f..190fb1bd5b 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -1113,7 +1113,11 @@ public:
return false;
}
- unsigned newTemp();
+ enum TempForWhom {
+ NewTempForCodegen,
+ NewTempForOptimizer
+ };
+ unsigned newTemp(TempForWhom tfw = NewTempForCodegen);
Temp *TEMP(unsigned kind);
ArgLocal *ARG(unsigned index, unsigned scope);
@@ -1278,6 +1282,7 @@ struct Function {
Module *module;
QQmlJS::MemoryPool *pool;
const QString *name;
+ int currentTemp = 0;
int tempCount;
int maxNumberOfArguments;
QSet<QString> strings;
@@ -1511,10 +1516,17 @@ protected:
BasicBlock *currentBB;
};
-inline unsigned BasicBlock::newTemp()
+inline unsigned BasicBlock::newTemp(TempForWhom tfw)
{
Q_ASSERT(!isRemoved());
- return function->tempCount++;
+
+ if (tfw == NewTempForOptimizer)
+ return function->tempCount++;
+
+ int t = function->currentTemp++;
+ if (function->tempCount < function->currentTemp)
+ function->tempCount = function->currentTemp;
+ return t;
}
inline Temp *BasicBlock::TEMP(unsigned index)
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index fc136b09ff..8cf5fac760 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -2770,7 +2770,7 @@ public:
} else if (Const *c = (*conversion.expr)->asConst()) {
convertConst(c, conversion.targetType);
} else if (ArgLocal *al = (*conversion.expr)->asArgLocal()) {
- Temp *target = bb->TEMP(bb->newTemp());
+ Temp *target = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer));
target->type = conversion.targetType;
Expr *convert = bb->CONVERT(al, conversion.targetType);
Move *convCall = f->NewStmt<Move>();
@@ -2791,7 +2791,7 @@ public:
*conversion.expr = source;
} else if (Temp *t = (*conversion.expr)->asTemp()) {
- Temp *target = bb->TEMP(bb->newTemp());
+ Temp *target = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer));
target->type = conversion.targetType;
Expr *convert = bb->CONVERT(t, conversion.targetType);
Move *convCall = f->NewStmt<Move>();
@@ -2820,7 +2820,7 @@ public:
// to:
// double{%3} = double{-double{%1}};
// int32{%2} = int32{convert(double{%3})};
- Temp *tmp = bb->TEMP(bb->newTemp());
+ Temp *tmp = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer));
tmp->type = u->type;
Move *extraMove = f->NewStmt<Move>();
worklist.registerNewStatement(extraMove);
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index 24257e99e9..b9d8ae0a6c 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -265,7 +265,7 @@ private:
QHash<BasicBlock *, BasicBlock *> startEndLoops;
};
-class Q_AUTOTEST_EXPORT MoveMapping
+class Q_QML_AUTOTEST_EXPORT MoveMapping
{
#ifdef V4_AUTOTEST
public:
diff --git a/src/qml/doc/images/cppintegration-ex.png b/src/qml/doc/images/cppintegration-ex.png
new file mode 100644
index 0000000000..0b476ccb93
--- /dev/null
+++ b/src/qml/doc/images/cppintegration-ex.png
Binary files differ
diff --git a/src/qml/doc/snippets/code/backend/backend.cpp b/src/qml/doc/snippets/code/backend/backend.cpp
new file mode 100644
index 0000000000..4a7ee89cec
--- /dev/null
+++ b/src/qml/doc/snippets/code/backend/backend.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "backend.h"
+
+BackEnd::BackEnd(QObject *parent) :
+ QObject(parent)
+{
+}
+
+QString BackEnd::userName()
+{
+ return m_userName;
+}
+
+void BackEnd::setUserName(const QString &userName)
+{
+ if (userName == m_userName)
+ return;
+
+ m_userName = userName;
+ emit userNameChanged();
+}
diff --git a/src/qml/doc/snippets/code/backend/backend.h b/src/qml/doc/snippets/code/backend/backend.h
new file mode 100644
index 0000000000..91bb766e1f
--- /dev/null
+++ b/src/qml/doc/snippets/code/backend/backend.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include <QObject>
+#include <QString>
+
+class BackEnd : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged)
+
+public:
+ explicit BackEnd(QObject *parent = nullptr);
+
+ QString userName();
+ void setUserName(const QString &userName);
+
+signals:
+ void userNameChanged();
+
+private:
+ QString m_userName;
+};
+
+#endif // BACKEND_H
diff --git a/src/qml/doc/snippets/code/backend/main.cpp b/src/qml/doc/snippets/code/backend/main.cpp
new file mode 100644
index 0000000000..d7a1bcbd4f
--- /dev/null
+++ b/src/qml/doc/snippets/code/backend/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+#include "backend.h"
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd");
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
diff --git a/src/qml/doc/snippets/code/backend/main.qml b/src/qml/doc/snippets/code/backend/main.qml
new file mode 100644
index 0000000000..3720da8412
--- /dev/null
+++ b/src/qml/doc/snippets/code/backend/main.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.0
+//![import]
+import io.qt.examples.backend 1.0
+//![import]
+
+ApplicationWindow {
+ id: root
+ width: 300
+ height: 480
+ visible: true
+
+//![backend]
+ BackEnd {
+ id: backend
+ }
+//![backend]
+
+//![username_input]
+ TextField {
+ text: backend.userName
+ placeholderText: qsTr("User name")
+ anchors.centerIn: parent
+
+ onTextChanged: backend.userName = text
+ }
+//![username_input]
+}
+
diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc
index 1aa3bb6ab5..22115395b1 100644
--- a/src/qml/doc/src/cppintegration/topic.qdoc
+++ b/src/qml/doc/src/cppintegration/topic.qdoc
@@ -27,7 +27,68 @@
/*!
\page qtqml-cppintegration-topic.html
\title Integrating QML and C++
-\brief Description of how to integrate QML and C++ code
+\brief Provides instruction to integrate QML and C++
+
+QML applications often need to handle more advanced and performance-intensive
+tasks in C++. The most common and quickest way to do this is to expose the C++
+class to the QML runtime, provided the C++ implementation is derived from
+QObject. Assuming that you have Qt 5.7 or later installed, the following
+step-by-step instructions guide you through the process of using the C++ class,
+BackEnd, in a QML application:
+
+\list 1
+
+\li Create a new project using the "Qt Quick Application" template in Qt Creator
+
+\note Uncheck the \uicontrol {With ui.qml file} option in the
+\uicontrol {Define Project Details} section of \uicontrol {New Project Wizard}.
+
+\li Add a new C++ class called \c BackEnd to the project and replace its header
+file contents with:
+
+\quotefile code/backend/backend.h
+
+The \c Q_PROPERTY macro declares a property that could be accessed from QML.
+
+\li Replace its C++ file contents with:
+
+\quotefile code/backend/backend.cpp
+
+The \c setUserName function emits the \c userNameChanged signal every time
+\c m_userName value changes. The signal can be handled from QML using the
+\c onUserNameChanged handler.
+
+\li Include \c "backend.h" in \c main.cpp and register the class as a QML type
+under a import URL as shown below:
+
+\quotefile code/backend/main.cpp
+
+The BackEnd class is registered as a type, which is accessible from QML by
+importing the URL, "\c{io.qt.examples.backend 1.0}".
+
+\li Replace the contents of \c main.qml with the following code:
+
+\quotefile code/backend/main.qml
+
+The \c BackEnd instance lets you access the \c userName property, which
+is updated when the TextField's \c text property changes.
+
+\endlist
+
+Now the application can be run.
+
+\borderedimage cppintegration-ex.png
+\caption Application running on Ubuntu
+
+Qt offers several methods to integrate C++ with QML, and the method discussed
+in this tutorial is just one of them. For more details about these methods,
+refer to \l{Overview - QML and C++ Integration}.
+*/
+
+/*!
+\page qtqml-cppintegration-overview.html
+\title Overview - QML and C++ Integration
+\brief Highlights important points about integrating C++ with QML.
QML is designed to be easily extensible through C++ code. The classes in the \l {Qt QML} module
enable QML objects to be loaded and manipulated from C++, and the nature of QML engine's
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index 896be07ed5..78546e1509 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -83,6 +83,15 @@ template <typename JITAssembler>
void Unop<JITAssembler>::generateUMinus(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
+
+ if (IR::Const *c = source->asConst()) {
+ if (c->value == 0 && source->type == IR::SInt32Type) {
+ // special case: minus integer 0 is 0, which is not what JS expects it to be, so always
+ // do a runtime call
+ generateRuntimeCall(_as, target, uMinus, PointerToValue(source));
+ return;
+ }
+ }
if (source->type == IR::SInt32Type) {
typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index df2af9de40..9737a18812 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1706,7 +1706,9 @@ ReturnedValue Runtime::method_div(const Value &left, const Value &right)
if (Value::integerCompatible(left, right)) {
int lval = left.integerValue();
int rval = right.integerValue();
- if (rval != 0 && (lval % rval == 0))
+ if (rval != 0 // division by zero should result in a NaN
+ && (lval % rval == 0) // fractions can't be stored in an int
+ && !(lval == 0 && rval < 0)) // 0 / -something results in -0.0
return Encode(int(lval / rval));
else
return Encode(double(lval) / rval);
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index d8779e0d12..fd516c9815 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -596,7 +596,7 @@ The following functions are also on the Qt object.
\li application.font
\endlist
- \sa Screen, Window, Window.screen
+ \sa Screen, Window, {QtQuick::Window::screen}{Window.screen}
*/
/*!
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index 4e4db086b0..93c3e8e00c 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -603,6 +603,12 @@ empty string.
*/
QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
{
+ if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) {
+ if (url.length() > 6)
+ return QLatin1Char(':') + url.midRef(6);
+ return QString();
+ }
+
if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
if (url.length() > 4)
return QLatin1Char(':') + url.midRef(4);
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index 3650df8f3a..2a567fac8d 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -548,6 +548,12 @@ void QuickTestResult::stringify(QQmlV4Function *args)
result = QString::fromLatin1("Qt.vector3d(%1, %2, %3)").arg(v3d.x()).arg(v3d.y()).arg(v3d.z());
break;
}
+ case QVariant::Url:
+ {
+ QUrl url = v.value<QUrl>();
+ result = QString::fromLatin1("Qt.url(%1)").arg(url.toString());
+ break;
+ }
default:
result = v.toString();
}
diff --git a/src/quick/doc/snippets/qml/regexp.qml b/src/quick/doc/snippets/qml/regexp.qml
new file mode 100644
index 0000000000..c30336d418
--- /dev/null
+++ b/src/quick/doc/snippets/qml/regexp.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.0
+//![0]
+TextInput {
+ id: hexNumber
+ validator: RegExpValidator { regExp: /[0-9A-F]+/ }
+}
+//![0]
diff --git a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
index 324fc9750f..47dcd6d98c 100644
--- a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
+++ b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc
@@ -87,6 +87,7 @@ To visualize data, bind the view's \c model property to a model and the
The club may decorate the members list by binding visual objects to the \c
header and \c footer properties. The visual object may be defined inline, in
another file, or in a \l {Component} type.
+
\snippet qml/listview-decorations.qml decorations
\image listview-decorations.png
@@ -102,7 +103,6 @@ To visualize data, bind the view's \c model property to a model and the
will always ensure that the \c currentIndex is within the highlight range
specified.
-
\section2 ListView Sections
\l {ListView} contents may be grouped into \e sections, where related list
@@ -195,7 +195,7 @@ To visualize data, bind the view's \c model property to a model and the
Positioning of items from a model can be achieved using a \l{Repeater}.
- \section2 ListModel
+ \section2 List Model
ListModel is a simple hierarchy of types specified in QML. The
available roles are specified by the \l ListElement properties.
@@ -222,7 +222,7 @@ To visualize data, bind the view's \c model property to a model and the
using the model. To reset the roles available in the model, call ListModel::clear().
- \section2 XmlListModel
+ \section2 XML Model
XmlListModel allows construction of a model from an XML data source. The roles
are specified via the \l XmlRole type. The type needs to be imported.
@@ -244,23 +244,44 @@ To visualize data, bind the view's \c model property to a model and the
}
\endqml
+ The \c query property specifies that the XmlListModel generates a model item
+ for each \c <item> in the XML document.
+
The \l{Qt Quick Demo - RSS News}{RSS News demo} shows how XmlListModel can
be used to display an RSS feed.
- \section2 VisualItemModel
+ \section2 Object Model
+
+ ObjectModel contains the visual items to be used in a view. When an ObjectModel
+ is used in a view, the view does not require a delegate because the ObjectModel
+ already contains the visual delegate (items).
- VisualItemModel allows QML items to be provided as a model.
+ The example below places three colored rectangles in a ListView.
- This model contains both the data and delegate; the child items of a
- VisualItemModel provide the contents of the delegate. The model
- does not provide any roles.
+ \code
+ import QtQuick 2.0
+ import QtQml.Models 2.1
+
+ Rectangle {
+ ObjectModel {
+ id: itemModel
+ Rectangle { height: 30; width: 80; color: "red" }
+ Rectangle { height: 30; width: 80; color: "green" }
+ Rectangle { height: 30; width: 80; color: "blue" }
+ }
- \snippet qml/models/visual-model-and-view.qml visual model and view
+ ListView {
+ anchors.fill: parent
+ model: itemModel
+ }
+ }
+ \endcode
- Note that in the above example there is no delegate required.
- The items of the model itself provide the visual types that
- will be positioned by the view.
+ \note VisualItemModel can also be used, but it is only provided for compatibility
+ reasons. VisualItemModel allows a QML item to be provided as a model. This model
+ contains both the data and delegate; the child items of a VisualItemModel
+ provide the contents of the delegate. The model does not provide any roles.
\section2 Integers as Models
@@ -357,8 +378,18 @@ rectangles for the Grid item to position in a 5 by 5 arrangement.
The number of items created by a Repeater is held by its \l{Repeater::}{count}
property. It is not possible to set this property to determine the number of
items to be created. Instead, as in the above example, we use an integer as
-the model. This is explained in the \l{qtquick-modelviewsdata-modelview.html#integers-as-models}{QML Data Models}
-document.
+the model.
+
+For more details, see the \l{qtquick-modelviewsdata-modelview.html#integers-as-models}{QML Data Models} document.
+
+If the model is a string list, the delegate is also exposed to a read-only
+\c modelData property that holds the string. For example:
+
+\table
+ \row
+ \li \snippet qml/repeaters/repeater.qml modeldata
+ \li \image repeater-modeldata.png
+\endtable
It is also possible to use a delegate as the template for the items created
by a Repeater. This is specified using the \l{Repeater::}{delegate} property.
diff --git a/src/quick/doc/src/concepts/positioning/layouts.qdoc b/src/quick/doc/src/concepts/positioning/layouts.qdoc
index 47ed2563f8..3824d17559 100644
--- a/src/quick/doc/src/concepts/positioning/layouts.qdoc
+++ b/src/quick/doc/src/concepts/positioning/layouts.qdoc
@@ -133,6 +133,5 @@ control of spacing between items and between lines of items.
There are several other ways to position items in a user interface. In addition
to the basic technique of specifying their coordinates directly, they can be
positioned relative to other items with \l{anchor-layout}{anchors}, or used
-with \l{QML Data Models} such as
-\l{QML Data Models#VisualItemModel}{VisualItemModel}.
+with \l{QML Data Models} such as \l{QML Data Models#Object Model}{Object Model}.
*/
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index fd78c46a16..c570b95a21 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -495,9 +495,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
// We've jumped more than a page. Estimate which items are now
// visible and fill from there.
int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
modelIndex += count;
if (modelIndex >= model->count())
modelIndex = model->count() - 1;
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 555db03962..084b1f197a 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -380,9 +380,7 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
int oldCount = dataModel->count();
dataModel->setDelegate(delegate);
if (isComponentComplete()) {
- for (FxViewItem *item : qAsConst(d->visibleItems))
- d->releaseItem(item);
- d->visibleItems.clear();
+ d->releaseVisibleItems();
d->releaseItem(d->currentItem);
d->currentItem = 0;
d->updateSectionCriteria();
@@ -1743,9 +1741,7 @@ void QQuickItemViewPrivate::clear()
currentChanges.reset();
timeline.clear();
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
visibleIndex = 0;
for (FxViewItem *item : qAsConst(releasePendingTransition)) {
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 3087682ac7..b6353246e8 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -269,6 +269,15 @@ public:
q->polish();
}
+ void releaseVisibleItems() {
+ // make a copy and clear the visibleItems first to avoid destroyed
+ // items being accessed during the loop (QTBUG-61294)
+ const QList<FxViewItem *> oldVisible = visibleItems;
+ visibleItems.clear();
+ for (FxViewItem *item : oldVisible)
+ releaseItem(item);
+ }
+
QPointer<QQmlInstanceModel> model;
QVariant modelVariant;
int itemCount;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index f739115e6b..18f9b8512d 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -660,9 +660,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
int newModelIdx = qBound(0, modelIndex + count, model->count());
count = newModelIdx - modelIndex;
if (count) {
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
modelIndex = newModelIdx;
visibleIndex = modelIndex;
visiblePos = itemEnd + count * (averageSize + spacing);
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 9ad7d27b18..6fc4c0553a 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -314,7 +314,11 @@ void QQuickRepeater::setDelegate(QQmlComponent *delegate)
/*!
\qmlproperty int QtQuick::Repeater::count
- This property holds the number of items in the repeater.
+ This property holds the number of items in the model.
+
+ \note The number of items in the model as reported by count may differ from
+ the number of created delegates if the Repeater is in the process of
+ instantiating delegates or is incorrectly set up.
*/
int QQuickRepeater::count() const
{
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
index 0f4a0ac8f5..307615a216 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
@@ -232,8 +232,8 @@ void QSGSoftwareRenderableNode::update()
m_boundingRectMin = QRect();
m_boundingRectMax = QRect();
} else {
- m_boundingRectMin = m_boundingRectMin.intersected(m_clipRegion.rects().first());
- m_boundingRectMax = m_boundingRectMax.intersected(m_clipRegion.rects().first());
+ m_boundingRectMin = m_boundingRectMin.intersected(m_clipRegion.rects().constFirst());
+ m_boundingRectMax = m_boundingRectMax.intersected(m_clipRegion.rects().constFirst());
}
}
diff --git a/src/quick/util/qquickvalidator.cpp b/src/quick/util/qquickvalidator.cpp
index a05117bd06..93f414fe80 100644
--- a/src/quick/util/qquickvalidator.cpp
+++ b/src/quick/util/qquickvalidator.cpp
@@ -219,6 +219,19 @@ void QQuickDoubleValidator::resetLocaleName()
matching "a".
By default, this property contains a regular expression with the pattern .* that matches any string.
+
+ Below you can find an example of a \l TextInput object with a RegExpValidator specified:
+
+ \snippet qml/regexp.qml 0
+
+ Some more examples of regular expressions:
+
+ \list
+ \li A list of numbers with one to three positions separated by a comma:
+ /\d{1,3}(?:,\d{1,3})+$/
+ \li An amount consisting of up to 3 numbers before the decimal point, and
+ 1 to 2 after the decimal point: \li /(\d{1,3})([.,]\d{1,2})?$/
+ \endlist
*/
#endif // validator