summaryrefslogtreecommitdiff
path: root/src/libs/qmljs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/qmljs')
-rwxr-xr-xsrc/libs/qmljs/parser/gen-parser.sh10
-rw-r--r--src/libs/qmljs/qmljs.qbs18
-rw-r--r--src/libs/qmljs/qmljscheck.cpp138
-rw-r--r--src/libs/qmljs/qmljscheck.h1
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp12
-rw-r--r--src/libs/qmljs/qmljsstaticanalysismessage.cpp11
-rw-r--r--src/libs/qmljs/qmljsstaticanalysismessage.h5
7 files changed, 171 insertions, 24 deletions
diff --git a/src/libs/qmljs/parser/gen-parser.sh b/src/libs/qmljs/parser/gen-parser.sh
index 1a755052e9..e6fdadf675 100755
--- a/src/libs/qmljs/parser/gen-parser.sh
+++ b/src/libs/qmljs/parser/gen-parser.sh
@@ -1,5 +1,15 @@
#!/bin/bash
+# This is the script that generates the copy of the QmlJS parser from the sources
+# in the qtdeclarative source tree.
+#
+# It applies a bunch of renames to make the source compatible with the Qt Creator
+# sources as well as rewrites of the licenses.
+#
+# Example:
+# cd src/libs/qmljs/parser
+# QTDIR=~/path/to/qtdeclarative-checkout ./gen-parser.sh
+
me=$(dirname $0)
for i in $QTDIR/src/qml/qml/parser/*.{g,h,cpp,pri}; do
diff --git a/src/libs/qmljs/qmljs.qbs b/src/libs/qmljs/qmljs.qbs
index d7b556b06b..6a4e8b0c21 100644
--- a/src/libs/qmljs/qmljs.qbs
+++ b/src/libs/qmljs/qmljs.qbs
@@ -4,11 +4,7 @@ import "../QtcLibrary.qbs" as QtcLibrary
QtcLibrary {
name: "QmlJS"
- cpp.includePaths: [
- ".",
- "..",
- "parser"
- ]
+ cpp.includePaths: base.concat("parser")
cpp.defines: base.concat([
"QMLJS_BUILD_DIR",
"QT_CREATOR"
@@ -21,6 +17,8 @@ QtcLibrary {
Depends { name: "Qt"; submodules: ["widgets", "script"] }
files: [
+ "jsoncheck.cpp",
+ "jsoncheck.h",
"qmljs.qrc",
"qmljs_global.h",
"qmljsbind.cpp",
@@ -55,6 +53,7 @@ QtcLibrary {
"qmljspropertyreader.cpp",
"qmljspropertyreader.h",
"qmljsreformatter.cpp",
+ "qmljsreformatter.h",
"qmljsrewriter.cpp",
"qmljsrewriter.h",
"qmljsscanner.cpp",
@@ -73,9 +72,6 @@ QtcLibrary {
"qmljsutils.h",
"qmljsvalueowner.cpp",
"qmljsvalueowner.h",
- "qmljsreformatter.h",
- "jsoncheck.cpp",
- "jsoncheck.h",
"images/element.png",
"images/func.png",
"images/property.png",
@@ -99,16 +95,12 @@ QtcLibrary {
"parser/qmljslexer_p.h",
"parser/qmljsmemorypool_p.h",
"parser/qmljsparser.cpp",
- "parser/qmljsparser_p.h"
+ "parser/qmljsparser_p.h",
]
ProductModule {
Depends { name: "cpp" }
Depends { name: "LanguageUtils" }
- cpp.includePaths: [
- ".",
- "parser"
- ]
cpp.defines: [
"QT_CREATOR"
]
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 1f46e4c58f..0fe58a6d15 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -502,8 +502,44 @@ private:
bool _seenNonDeclarationStatement;
};
+class VisualAspectsPropertyBlackList : public QStringList
+{
+public:
+ VisualAspectsPropertyBlackList()
+ {
+ (*this) << QLatin1String("x") << QLatin1String("y") << QLatin1String("z")
+ << QLatin1String("width") << QLatin1String("height") << QLatin1String("color")
+ << QLatin1String("opacity") << QLatin1String("scale")
+ << QLatin1String("rotation") << QLatin1String("margins")
+ << QLatin1String("verticalCenterOffset") << QLatin1String("horizontalCenterOffset")
+ << QLatin1String("baselineOffset") << QLatin1String("bottomMargin")
+ << QLatin1String("topMargin") << QLatin1String("leftMargin")
+ << QLatin1String("rightMargin") << QLatin1String("baseline")
+ << QLatin1String("centerIn") << QLatin1String("fill")
+ << QLatin1String("left") << QLatin1String("right")
+ << QLatin1String("mirrored") << QLatin1String("verticalCenter")
+ << QLatin1String("horizontalCenter");
+
+ }
+};
+
+class UnsupportedTypesByVisualDesigner : public QStringList
+{
+public:
+ UnsupportedTypesByVisualDesigner()
+ {
+ (*this) << QLatin1String("Transform") << QLatin1String("Timer")
+ << QLatin1String("Rotation") << QLatin1String("Scale")
+ << QLatin1String("Translate") << QLatin1String("Package")
+ << QLatin1String("Particles");
+ }
+
+};
} // end of anonymous namespace
+Q_GLOBAL_STATIC(VisualAspectsPropertyBlackList, visualAspectsPropertyBlackList)
+Q_GLOBAL_STATIC(UnsupportedTypesByVisualDesigner, unsupportedTypesByVisualDesigner)
+
Check::Check(Document::Ptr doc, const ContextPtr &context)
: _doc(doc)
, _context(context)
@@ -523,6 +559,11 @@ Check::Check(Document::Ptr doc, const ContextPtr &context)
disableMessage(HintBinaryOperatorSpacing);
disableMessage(HintOneStatementPerLine);
disableMessage(HintExtraParentheses);
+ disableMessage(WarnImperativeCodeNotEditableInVisualDesigner);
+ disableMessage(WarnUnsupportedTypeInVisualDesigner);
+ disableMessage(WarnReferenceToParentItemNotSupportedByVisualDesigner);
+ disableMessage(WarnUndefinedValueForVisualDesigner);
+ disableMessage(WarnStatesOnlyInRootItemForVisualDesigner);
}
Check::~Check()
@@ -568,21 +609,28 @@ bool Check::visit(UiProgram *)
bool Check::visit(UiObjectInitializer *)
{
+ QString typeName;
m_propertyStack.push(StringSet());
- UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent());
- if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == "Component")
- m_idStack.push(StringSet());
- UiObjectBinding *objectBinding = cast<UiObjectBinding *>(parent());
- if (objectBinding && objectBinding->qualifiedTypeNameId->name == "Component")
- m_idStack.push(StringSet());
+ UiQualifiedId *qualifiedTypeId = qualifiedTypeNameId(parent());
+ if (qualifiedTypeId) {
+ typeName = qualifiedTypeId->name.toString();
+ if (typeName == QLatin1String("Component"))
+ m_idStack.push(StringSet());
+ }
+
+ if (!typeName.isEmpty() && typeName.at(0).isUpper())
+ m_typeStack.push(typeName);
+
if (m_idStack.isEmpty())
m_idStack.push(StringSet());
+
return true;
}
void Check::endVisit(UiObjectInitializer *)
{
m_propertyStack.pop();
+ m_typeStack.pop();
UiObjectDefinition *objectDenition = cast<UiObjectDefinition *>(parent());
if (objectDenition && objectDenition->qualifiedTypeNameId->name == "Component")
m_idStack.pop();
@@ -618,6 +666,57 @@ bool Check::visit(UiObjectBinding *ast)
return false;
}
+static bool expressionAffectsVisualAspects(BinaryExpression *expression)
+{
+ if (expression->op == QSOperator::Assign
+ || expression->op == QSOperator::InplaceSub
+ || expression->op == QSOperator::InplaceAdd
+ || expression->op == QSOperator::InplaceDiv
+ || expression->op == QSOperator::InplaceMul
+ || expression->op == QSOperator::InplaceOr
+ || expression->op == QSOperator::InplaceXor
+ || expression->op == QSOperator::InplaceAnd) {
+
+ const ExpressionNode *lhsValue = expression->left;
+
+ if (const IdentifierExpression* identifierExpression = cast<const IdentifierExpression *>(lhsValue)) {
+ if (visualAspectsPropertyBlackList()->contains(identifierExpression->name.toString()))
+ return true;
+ } else if (const FieldMemberExpression* fieldMemberExpression = cast<const FieldMemberExpression *>(lhsValue)) {
+ if (visualAspectsPropertyBlackList()->contains(fieldMemberExpression->name.toString()))
+ return true;
+ }
+ }
+ return false;
+}
+
+static UiQualifiedId *getRightMostIdentifier(UiQualifiedId *typeId)
+{
+ if (typeId->next)
+ return getRightMostIdentifier(typeId->next);
+
+ return typeId;
+}
+
+static bool checkTypeForDesignerSupport(UiQualifiedId *typeId)
+{
+ return unsupportedTypesByVisualDesigner()->contains(getRightMostIdentifier(typeId)->name.toString());
+}
+
+static bool checkTopLevelBindingForParentReference(ExpressionStatement *expStmt, const QString &source)
+{
+ if (!expStmt)
+ return false;
+
+ SourceLocation location = locationFromRange(expStmt->firstSourceLocation(), expStmt->lastSourceLocation());
+ QString stmtSource = source.mid(location.begin(), location.length);
+
+ if (stmtSource.contains(QRegExp("(^|\\W)parent\\.")))
+ return true;
+
+ return false;
+}
+
void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
UiObjectInitializer *initializer)
{
@@ -629,9 +728,16 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
return;
}
+ const SourceLocation typeErrorLocation = fullLocationForQualifiedId(typeId);
+
+ if (checkTypeForDesignerSupport(typeId))
+ addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation);
+
+ if (m_typeStack.count() > 1 && getRightMostIdentifier(typeId)->name.toString() == QLatin1String("State"))
+ addMessage(WarnStatesOnlyInRootItemForVisualDesigner, typeErrorLocation);
+
bool typeError = false;
if (_importsOk) {
- const SourceLocation typeErrorLocation = fullLocationForQualifiedId(typeId);
const ObjectValue *prototype = _context->lookupType(_doc.data(), typeId);
if (!prototype) {
typeError = true;
@@ -711,6 +817,13 @@ bool Check::visit(UiScriptBinding *ast)
m_idStack.top().insert(id);
}
+ if (m_typeStack.count() == 1
+ && visualAspectsPropertyBlackList()->contains(ast->qualifiedId->name.toString())
+ && checkTopLevelBindingForParentReference(cast<ExpressionStatement *>(ast->statement), _doc->source())) {
+ addMessage(WarnReferenceToParentItemNotSupportedByVisualDesigner,
+ locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()));
+ }
+
checkProperty(ast->qualifiedId);
if (!ast->statement)
@@ -721,6 +834,12 @@ bool Check::visit(UiScriptBinding *ast)
Evaluate evaluator(&_scopeChain);
const Value *rhsValue = evaluator(ast->statement);
+ if (visualAspectsPropertyBlackList()->contains(ast->qualifiedId->name.toString()) &&
+ rhsValue->asUndefinedValue()) {
+ addMessage(WarnUndefinedValueForVisualDesigner,
+ locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()));
+ }
+
const SourceLocation loc = locationFromRange(ast->statement->firstSourceLocation(),
ast->statement->lastSourceLocation());
AssignmentCheck assignmentCheck;
@@ -910,6 +1029,11 @@ bool Check::visit(BinaryExpression *ast)
addMessage(HintBinaryOperatorSpacing, op);
}
+ SourceLocation expressionSourceLocation = locationFromRange(ast->firstSourceLocation(),
+ ast->lastSourceLocation());
+ if (expressionAffectsVisualAspects(ast))
+ addMessage(WarnImperativeCodeNotEditableInVisualDesigner, expressionSourceLocation);
+
// check ==, !=
if (ast->op == QSOperator::Equal || ast->op == QSOperator::NotEqual) {
Evaluate eval(&_scopeChain);
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index e39493cf3c..9cdb0df1ad 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -132,6 +132,7 @@ private:
QList<AST::Node *> _chain;
QStack<StringSet> m_idStack;
QStack<StringSet> m_propertyStack;
+ QStack<QString> m_typeStack;
class MessageTypeAndSuppression
{
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 1ab8d8d7a9..0c7126582f 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -1357,7 +1357,8 @@ template void CppQmlTypes::load< QHash<QString, FakeMetaObject::ConstPtr> >(cons
QList<const CppComponentValue *> CppQmlTypes::createObjectsForImport(const QString &package, ComponentVersion version)
{
- QList<const CppComponentValue *> exportedObjects;
+ QHash<QString, const CppComponentValue *> exportedObjects;
+
QList<const CppComponentValue *> newObjects;
// make new exported objects
@@ -1397,8 +1398,11 @@ QList<const CppComponentValue *> CppQmlTypes::createObjectsForImport(const QStri
// use package.cppname importversion as key
_objectsByQualifiedName.insert(key, newComponent);
- if (exported)
- exportedObjects += newComponent;
+ if (exported) {
+ if (!exportedObjects.contains(name) // we might have the same type in different versions
+ || (newComponent->componentVersion() > exportedObjects.value(name)->componentVersion()))
+ exportedObjects.insert(name, newComponent);
+ }
newObjects += newComponent;
}
}
@@ -1436,7 +1440,7 @@ QList<const CppComponentValue *> CppQmlTypes::createObjectsForImport(const QStri
}
}
- return exportedObjects;
+ return exportedObjects.values();
}
bool CppQmlTypes::hasModule(const QString &module) const
diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.cpp b/src/libs/qmljs/qmljsstaticanalysismessage.cpp
index bd0a79e79d..8da87b317e 100644
--- a/src/libs/qmljs/qmljsstaticanalysismessage.cpp
+++ b/src/libs/qmljs/qmljsstaticanalysismessage.cpp
@@ -214,6 +214,17 @@ StaticAnalysisMessages::StaticAnalysisMessages()
tr("maximum string value length is %1"), 1);
newMsg(ErrInvalidArrayValueLength, Error,
tr("%1 elements expected in array value"), 1);
+ newMsg(WarnImperativeCodeNotEditableInVisualDesigner, Warning,
+ tr("Imperative code is not supported in the Qt Quick Designer"));
+ newMsg(WarnUnsupportedTypeInVisualDesigner, Warning,
+ tr("This type is not supported in the Qt Quick Designer"));
+ newMsg(WarnReferenceToParentItemNotSupportedByVisualDesigner, Warning,
+ tr("Reference to parent item cannot be resolved correctly by the Qt Quick Designer"));
+ newMsg(WarnUndefinedValueForVisualDesigner, Warning,
+ tr("This visual property binding cannot be evaluted in the local context "
+ "and might not show up in Qt Quick Designer as expected"));
+ newMsg(WarnStatesOnlyInRootItemForVisualDesigner, Warning,
+ tr("Qt Quick Designer only supports states in the root item "));
}
} // anonymous namespace
diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.h b/src/libs/qmljs/qmljsstaticanalysismessage.h
index b1f5999775..6b40ebfb01 100644
--- a/src/libs/qmljs/qmljsstaticanalysismessage.h
+++ b/src/libs/qmljs/qmljsstaticanalysismessage.h
@@ -100,6 +100,11 @@ enum Type
WarnConfusingExpressionStatement = 127,
HintDeclarationsShouldBeAtStartOfFunction = 201,
HintOneStatementPerLine = 202,
+ WarnImperativeCodeNotEditableInVisualDesigner = 203,
+ WarnUnsupportedTypeInVisualDesigner = 204,
+ WarnReferenceToParentItemNotSupportedByVisualDesigner = 205,
+ WarnUndefinedValueForVisualDesigner = 206,
+ WarnStatesOnlyInRootItemForVisualDesigner = 207,
ErrUnknownComponent = 300,
ErrCouldNotResolvePrototypeOf = 301,
ErrCouldNotResolvePrototype = 302,