diff options
Diffstat (limited to 'src/libs/qmljs')
-rwxr-xr-x | src/libs/qmljs/parser/gen-parser.sh | 10 | ||||
-rw-r--r-- | src/libs/qmljs/qmljs.qbs | 18 | ||||
-rw-r--r-- | src/libs/qmljs/qmljscheck.cpp | 138 | ||||
-rw-r--r-- | src/libs/qmljs/qmljscheck.h | 1 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.cpp | 12 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsstaticanalysismessage.cpp | 11 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsstaticanalysismessage.h | 5 |
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, |