forked from qt-creator/qt-creator
QmlJSCheck: adding more checks
We are checking for duplicate ids and duplicate property definitions now.
This commit is contained in:
@@ -72,6 +72,20 @@ SourceLocation QmlJS::locationFromRange(const SourceLocation &start,
|
|||||||
start.startColumn);
|
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)
|
DiagnosticMessage QmlJS::errorMessage(const AST::SourceLocation &loc, const QString &message)
|
||||||
{
|
{
|
||||||
return DiagnosticMessage(DiagnosticMessage::Error, loc, message);
|
return DiagnosticMessage(DiagnosticMessage::Error, loc, message);
|
||||||
@@ -387,6 +401,29 @@ bool Check::visit(UiProgram *)
|
|||||||
return true;
|
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)
|
bool Check::visit(UiObjectDefinition *ast)
|
||||||
{
|
{
|
||||||
visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
|
visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
|
||||||
@@ -396,6 +433,7 @@ bool Check::visit(UiObjectDefinition *ast)
|
|||||||
bool Check::visit(UiObjectBinding *ast)
|
bool Check::visit(UiObjectBinding *ast)
|
||||||
{
|
{
|
||||||
checkScopeObjectMember(ast->qualifiedId);
|
checkScopeObjectMember(ast->qualifiedId);
|
||||||
|
checkProperty(ast->qualifiedId);
|
||||||
|
|
||||||
visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
|
visitQmlObject(ast, ast->qualifiedTypeNameId, ast->initializer);
|
||||||
return false;
|
return false;
|
||||||
@@ -457,12 +495,20 @@ bool Check::visit(UiScriptBinding *ast)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id.isEmpty() || ! id[0].isLower()) {
|
if (id.isEmpty() || (!id[0].isLower() && id[0] != '_')) {
|
||||||
error(loc, Check::tr("ids must be lower case"));
|
error(loc, Check::tr("ids must be lower case or start with underscore"));
|
||||||
return false;
|
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);
|
const Value *lhsValue = checkScopeObjectMember(ast->qualifiedId);
|
||||||
if (lhsValue) {
|
if (lhsValue) {
|
||||||
// ### Fix the evaluator to accept statements!
|
// ### Fix the evaluator to accept statements!
|
||||||
@@ -493,6 +539,7 @@ bool Check::visit(UiScriptBinding *ast)
|
|||||||
bool Check::visit(UiArrayBinding *ast)
|
bool Check::visit(UiArrayBinding *ast)
|
||||||
{
|
{
|
||||||
checkScopeObjectMember(ast->qualifiedId);
|
checkScopeObjectMember(ast->qualifiedId);
|
||||||
|
checkProperty(ast->qualifiedId);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
#include <QtCore/QSet>
|
||||||
|
#include <QtCore/QStack>
|
||||||
#include <QtGui/QColor>
|
#include <QtGui/QColor>
|
||||||
|
|
||||||
namespace QmlJS {
|
namespace QmlJS {
|
||||||
@@ -44,12 +46,18 @@ class QMLJS_EXPORT Check: protected AST::Visitor
|
|||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(QmlJS::Check)
|
Q_DECLARE_TR_FUNCTIONS(QmlJS::Check)
|
||||||
|
|
||||||
|
typedef QSet<QString> StringSet;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Check(Document::Ptr doc, const Snapshot &snapshot, const Interpreter::Context *linkedContextNoScope);
|
Check(Document::Ptr doc, const Snapshot &snapshot, const Interpreter::Context *linkedContextNoScope);
|
||||||
virtual ~Check();
|
virtual ~Check();
|
||||||
|
|
||||||
QList<DiagnosticMessage> operator()();
|
QList<DiagnosticMessage> operator()();
|
||||||
|
|
||||||
|
|
||||||
|
void setIgnoreTypeErrors(bool ignore)
|
||||||
|
{ _ignoreTypeErrors = ignore; }
|
||||||
|
|
||||||
enum Option {
|
enum Option {
|
||||||
WarnDangerousNonStrictEqualityChecks = 1 << 0,
|
WarnDangerousNonStrictEqualityChecks = 1 << 0,
|
||||||
WarnAllNonStrictEqualityChecks = 1 << 1,
|
WarnAllNonStrictEqualityChecks = 1 << 1,
|
||||||
@@ -79,6 +87,7 @@ protected:
|
|||||||
virtual bool visit(AST::FieldMemberExpression *ast);
|
virtual bool visit(AST::FieldMemberExpression *ast);
|
||||||
virtual bool visit(AST::FunctionDeclaration *ast);
|
virtual bool visit(AST::FunctionDeclaration *ast);
|
||||||
virtual bool visit(AST::FunctionExpression *ast);
|
virtual bool visit(AST::FunctionExpression *ast);
|
||||||
|
virtual bool visit(AST::UiObjectInitializer *);
|
||||||
|
|
||||||
virtual bool visit(AST::BinaryExpression *ast);
|
virtual bool visit(AST::BinaryExpression *ast);
|
||||||
virtual bool visit(AST::Block *ast);
|
virtual bool visit(AST::Block *ast);
|
||||||
@@ -94,12 +103,15 @@ protected:
|
|||||||
virtual bool visit(AST::CaseClause *ast);
|
virtual bool visit(AST::CaseClause *ast);
|
||||||
virtual bool visit(AST::DefaultClause *ast);
|
virtual bool visit(AST::DefaultClause *ast);
|
||||||
|
|
||||||
|
virtual void endVisit(QmlJS::AST::UiObjectInitializer *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId,
|
void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId,
|
||||||
AST::UiObjectInitializer *initializer);
|
AST::UiObjectInitializer *initializer);
|
||||||
const Interpreter::Value *checkScopeObjectMember(const AST::UiQualifiedId *id);
|
const Interpreter::Value *checkScopeObjectMember(const AST::UiQualifiedId *id);
|
||||||
void checkAssignInCondition(AST::ExpressionNode *condition);
|
void checkAssignInCondition(AST::ExpressionNode *condition);
|
||||||
void checkEndsWithControlFlow(AST::StatementList *statements, AST::SourceLocation errorLoc);
|
void checkEndsWithControlFlow(AST::StatementList *statements, AST::SourceLocation errorLoc);
|
||||||
|
void checkProperty(QmlJS::AST::UiQualifiedId *);
|
||||||
|
|
||||||
void warning(const AST::SourceLocation &loc, const QString &message);
|
void warning(const AST::SourceLocation &loc, const QString &message);
|
||||||
void error(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;
|
const Interpreter::Value *_lastValue;
|
||||||
QList<AST::Node *> _chain;
|
QList<AST::Node *> _chain;
|
||||||
|
QSet<QString> m_ids;
|
||||||
|
QStack<StringSet> m_propertyStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
QMLJS_EXPORT QColor toQColor(const QString &qmlColorString);
|
QMLJS_EXPORT QColor toQColor(const QString &qmlColorString);
|
||||||
|
|
||||||
QMLJS_EXPORT AST::SourceLocation locationFromRange(const AST::SourceLocation &start,
|
QMLJS_EXPORT AST::SourceLocation locationFromRange(const AST::SourceLocation &start,
|
||||||
const AST::SourceLocation &end);
|
const AST::SourceLocation &end);
|
||||||
|
|
||||||
|
QMLJS_EXPORT AST::SourceLocation fullLocationForQualifiedId(AST::UiQualifiedId *);
|
||||||
|
|
||||||
QMLJS_EXPORT DiagnosticMessage errorMessage(const AST::SourceLocation &loc,
|
QMLJS_EXPORT DiagnosticMessage errorMessage(const AST::SourceLocation &loc,
|
||||||
const QString &message);
|
const QString &message);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user