From e850586b770ab9330347354b01c31eff1053ad78 Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Tue, 6 Sep 2011 12:59:30 +0200
Subject: [PATCH] QmlJS checks: Warn about inappropriate use of constructor
 functions.

Change-Id: Iaedaaa88915f2010bfdd0d2b5ca95f01f8663ed7
Reviewed-on: http://codereview.qt.nokia.com/4254
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
---
 src/libs/qmljs/qmljscheck.cpp | 61 +++++++++++++++++++++++++++++++++--
 src/libs/qmljs/qmljscheck.h   |  8 ++++-
 2 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 71257250e2a..90aa25b11aa 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -408,9 +408,10 @@ Check::Check(Document::Ptr doc, const ContextPtr &context)
     , _scopeChain(doc, _context)
     , _scopeBuilder(&_scopeChain)
     , _options(WarnDangerousNonStrictEqualityChecks | WarnBlocks | WarnWith
-          | WarnVoid | WarnCommaExpression | WarnExpressionStatement
-          | WarnAssignInCondition | WarnUseBeforeDeclaration | WarnDuplicateDeclaration
-          | WarnCaseWithoutFlowControlEnd | ErrCheckTypeErrors)
+               | WarnVoid | WarnCommaExpression | WarnExpressionStatement
+               | WarnAssignInCondition | WarnUseBeforeDeclaration | WarnDuplicateDeclaration
+               | WarnCaseWithoutFlowControlEnd | WarnNonCapitalizedNew
+               | WarnCallsOfCapitalizedFunctions | ErrCheckTypeErrors)
     , _lastValue(0)
 {
 }
@@ -891,6 +892,60 @@ bool Check::visit(DefaultClause *ast)
     return true;
 }
 
+static QString functionName(ExpressionNode *ast, SourceLocation *location)
+{
+    if (IdentifierExpression *id = cast<IdentifierExpression *>(ast)) {
+        if (id->name) {
+            *location = id->identifierToken;
+            return id->name->asString();
+        }
+    } else if (FieldMemberExpression *fme = cast<FieldMemberExpression *>(ast)) {
+        if (fme->name) {
+            *location = fme->identifierToken;
+            return fme->name->asString();
+        }
+    }
+    return QString();
+}
+
+void Check::checkNewExpression(ExpressionNode *ast)
+{
+    if (!(_options & WarnNonCapitalizedNew))
+        return;
+    SourceLocation location;
+    const QString name = functionName(ast, &location);
+    if (name.isEmpty())
+        return;
+    if (!name.at(0).isUpper()) {
+        warning(location, tr("'new' should only be used with functions that start with an uppercase letter"));
+    }
+}
+
+bool Check::visit(NewExpression *ast)
+{
+    checkNewExpression(ast->expression);
+    return true;
+}
+
+bool Check::visit(NewMemberExpression *ast)
+{
+    checkNewExpression(ast->base);
+    return true;
+}
+
+bool Check::visit(CallExpression *ast)
+{
+    // check for capitalized function name being called
+    if (_options & WarnCallsOfCapitalizedFunctions) {
+        SourceLocation location;
+        const QString name = functionName(ast->base, &location);
+        if (!name.isEmpty() && name.at(0).isUpper()) {
+            warning(location, tr("calls of functions that start with an uppercase letter should use 'new'"));
+        }
+    }
+    return true;
+}
+
 /// When something is changed here, also change ReadingContext::lookupProperty in
 /// texttomodelmerger.cpp
 /// ### Maybe put this into the context as a helper method.
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index af4b75c2c3c..310d91880f8 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -72,7 +72,9 @@ public:
         WarnDuplicateDeclaration             = 1 << 9,
         WarnDeclarationsNotStartOfFunction   = 1 << 10,
         WarnCaseWithoutFlowControlEnd        = 1 << 11,
-        ErrCheckTypeErrors                   = 1 << 12
+        WarnNonCapitalizedNew                = 1 << 12,
+        WarnCallsOfCapitalizedFunctions      = 1 << 13,
+        ErrCheckTypeErrors                   = 1 << 14
     };
     Q_DECLARE_FLAGS(Options, Option)
 
@@ -111,6 +113,9 @@ protected:
     virtual bool visit(AST::DoWhileStatement *ast);
     virtual bool visit(AST::CaseClause *ast);
     virtual bool visit(AST::DefaultClause *ast);
+    virtual bool visit(AST::NewExpression *ast);
+    virtual bool visit(AST::NewMemberExpression *ast);
+    virtual bool visit(AST::CallExpression *ast);
 
     virtual void endVisit(QmlJS::AST::UiObjectInitializer *);
 
@@ -121,6 +126,7 @@ private:
     void checkAssignInCondition(AST::ExpressionNode *condition);
     void checkEndsWithControlFlow(AST::StatementList *statements, AST::SourceLocation errorLoc);
     void checkProperty(QmlJS::AST::UiQualifiedId *);
+    void checkNewExpression(AST::ExpressionNode *node);
 
     void warning(const AST::SourceLocation &loc, const QString &message);
     void error(const AST::SourceLocation &loc, const QString &message);
-- 
GitLab