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);
|
||||
}
|
||||
|
||||
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,11 +495,19 @@ 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) {
|
||||
@@ -493,6 +539,7 @@ bool Check::visit(UiScriptBinding *ast)
|
||||
bool Check::visit(UiArrayBinding *ast)
|
||||
{
|
||||
checkScopeObjectMember(ast->qualifiedId);
|
||||
checkProperty(ast->qualifiedId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QStack>
|
||||
#include <QtGui/QColor>
|
||||
|
||||
namespace QmlJS {
|
||||
@@ -44,12 +46,18 @@ class QMLJS_EXPORT Check: protected AST::Visitor
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(QmlJS::Check)
|
||||
|
||||
typedef QSet<QString> StringSet;
|
||||
|
||||
public:
|
||||
Check(Document::Ptr doc, const Snapshot &snapshot, const Interpreter::Context *linkedContextNoScope);
|
||||
virtual ~Check();
|
||||
|
||||
QList<DiagnosticMessage> 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<AST::Node *> _chain;
|
||||
QSet<QString> m_ids;
|
||||
QStack<StringSet> 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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user