From 0eb18f850ebcff530111ef6a00a87938d6e51f92 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 7 Dec 2010 17:31:53 +0100 Subject: [PATCH] QmlJSCheck: adding more checks We are checking for duplicate ids and duplicate property definitions now. --- src/libs/qmljs/qmljscheck.cpp | 51 +++++++++++++++++++++++++++++++++-- src/libs/qmljs/qmljscheck.h | 17 ++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index a144597388c..275d408a2a4 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -72,6 +72,20 @@ SourceLocation QmlJS::locationFromRange(const SourceLocation &start, start.startColumn); } +SourceLocation QmlJS::fullLocationForQualifiedId(AST::UiQualifiedId *qualifiedId) +{ + SourceLocation start = qualifiedId->identifierToken; + SourceLocation end = qualifiedId->identifierToken; + + for (UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) { + if (iter->name) + end = iter->identifierToken; + } + + return locationFromRange(start, end); +} + + DiagnosticMessage QmlJS::errorMessage(const AST::SourceLocation &loc, const QString &message) { return DiagnosticMessage(DiagnosticMessage::Error, loc, message); @@ -387,6 +401,29 @@ bool Check::visit(UiProgram *) return true; } +bool Check::visit(UiObjectInitializer *) +{ + m_propertyStack.push(StringSet()); + return true; +} + +void Check::endVisit(UiObjectInitializer *) +{ + m_propertyStack.pop(); +} + +void Check::checkProperty(UiQualifiedId *qualifiedId) +{ + const QString id = Bind::toString(qualifiedId); + if (id.at(0).isLower()) { + if (m_propertyStack.top().contains(id)) { + error(fullLocationForQualifiedId(qualifiedId), + Check::tr("properties can only be assigned once")); + } + m_propertyStack.top().insert(id); + } +} + bool Check::visit(UiObjectDefinition *ast) { visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer); @@ -396,6 +433,7 @@ bool Check::visit(UiObjectDefinition *ast) bool Check::visit(UiObjectBinding *ast) { checkScopeObjectMember(ast->qualifiedId); + checkProperty(ast->qualifiedId); visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer); return false; @@ -457,12 +495,20 @@ bool Check::visit(UiScriptBinding *ast) return false; } - if (id.isEmpty() || ! id[0].isLower()) { - error(loc, Check::tr("ids must be lower case")); + if (id.isEmpty() || (!id[0].isLower() && id[0] != '_')) { + error(loc, Check::tr("ids must be lower case or start with underscore")); return false; } + + if (m_ids.contains(id)) { + error(loc, Check::tr("ids must be unique")); + return false; + } + m_ids.insert(id); } + checkProperty(ast->qualifiedId); + const Value *lhsValue = checkScopeObjectMember(ast->qualifiedId); if (lhsValue) { // ### Fix the evaluator to accept statements! @@ -493,6 +539,7 @@ bool Check::visit(UiScriptBinding *ast) bool Check::visit(UiArrayBinding *ast) { checkScopeObjectMember(ast->qualifiedId); + checkProperty(ast->qualifiedId); return true; } diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h index 1c471b15a2c..9bbb6595faf 100644 --- a/src/libs/qmljs/qmljscheck.h +++ b/src/libs/qmljs/qmljscheck.h @@ -36,6 +36,8 @@ #include #include +#include +#include #include namespace QmlJS { @@ -44,12 +46,18 @@ class QMLJS_EXPORT Check: protected AST::Visitor { Q_DECLARE_TR_FUNCTIONS(QmlJS::Check) + typedef QSet StringSet; + public: Check(Document::Ptr doc, const Snapshot &snapshot, const Interpreter::Context *linkedContextNoScope); virtual ~Check(); QList operator()(); + + void setIgnoreTypeErrors(bool ignore) + { _ignoreTypeErrors = ignore; } + enum Option { WarnDangerousNonStrictEqualityChecks = 1 << 0, WarnAllNonStrictEqualityChecks = 1 << 1, @@ -79,6 +87,7 @@ protected: virtual bool visit(AST::FieldMemberExpression *ast); virtual bool visit(AST::FunctionDeclaration *ast); virtual bool visit(AST::FunctionExpression *ast); + virtual bool visit(AST::UiObjectInitializer *); virtual bool visit(AST::BinaryExpression *ast); virtual bool visit(AST::Block *ast); @@ -94,12 +103,15 @@ protected: virtual bool visit(AST::CaseClause *ast); virtual bool visit(AST::DefaultClause *ast); + virtual void endVisit(QmlJS::AST::UiObjectInitializer *); + private: void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId, AST::UiObjectInitializer *initializer); const Interpreter::Value *checkScopeObjectMember(const AST::UiQualifiedId *id); void checkAssignInCondition(AST::ExpressionNode *condition); void checkEndsWithControlFlow(AST::StatementList *statements, AST::SourceLocation errorLoc); + void checkProperty(QmlJS::AST::UiQualifiedId *); void warning(const AST::SourceLocation &loc, const QString &message); void error(const AST::SourceLocation &loc, const QString &message); @@ -119,12 +131,17 @@ private: const Interpreter::Value *_lastValue; QList _chain; + QSet m_ids; + QStack m_propertyStack; }; QMLJS_EXPORT QColor toQColor(const QString &qmlColorString); QMLJS_EXPORT AST::SourceLocation locationFromRange(const AST::SourceLocation &start, const AST::SourceLocation &end); + +QMLJS_EXPORT AST::SourceLocation fullLocationForQualifiedId(AST::UiQualifiedId *); + QMLJS_EXPORT DiagnosticMessage errorMessage(const AST::SourceLocation &loc, const QString &message);