From 6ca5f5f5f886449f88d1ff7085f640c46bbc8fb2 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Thu, 4 Feb 2010 16:31:29 +0100
Subject: [PATCH] Added semantic checks for compound expressions.

---
 src/libs/cplusplus/ResolveExpression.cpp |  6 ++-
 src/shared/cplusplus/AST.h               | 17 +++++---
 src/shared/cplusplus/CheckExpression.cpp |  5 ++-
 src/shared/cplusplus/CheckStatement.cpp  | 51 +++++++++++++++++-------
 src/shared/cplusplus/CheckStatement.h    |  8 +++-
 src/shared/cplusplus/Parser.cpp          |  8 ++++
 src/shared/cplusplus/Semantic.cpp        |  4 +-
 src/shared/cplusplus/Semantic.h          |  2 +-
 8 files changed, 74 insertions(+), 27 deletions(-)

diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index c6f8bd4b5b8..2425fef4226 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -295,7 +295,11 @@ bool ResolveExpression::visit(ThisExpressionAST *)
 
 bool ResolveExpression::visit(CompoundExpressionAST *ast)
 {
-    return true; // ###
+    CompoundStatementAST *cStmt = ast->compoundStatement;
+    if (cStmt && cStmt->statement_list) {
+        accept(cStmt->statement_list->lastValue());
+    }
+    return false;
 }
 
 bool ResolveExpression::visit(NestedExpressionAST *ast)
diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h
index c719f311608..1766891cd7b 100644
--- a/src/shared/cplusplus/AST.h
+++ b/src/shared/cplusplus/AST.h
@@ -80,6 +80,17 @@ public:
     }
 
     unsigned lastToken() const
+    {
+        _Tp lv = lastValue();
+
+        if (lv)
+            return lv->lastToken();
+
+        // ### assert(0);
+        return 0;
+    }
+
+    _Tp lastValue() const
     {
         _Tp lastValue = 0;
 
@@ -88,11 +99,7 @@ public:
                 lastValue = it->value;
         }
 
-        if (lastValue)
-            return lastValue->lastToken();
-
-        // ### assert(0);
-        return 0;
+        return lastValue;
     }
     
     _Tp value;
diff --git a/src/shared/cplusplus/CheckExpression.cpp b/src/shared/cplusplus/CheckExpression.cpp
index c971204c2e4..748fa9c9014 100644
--- a/src/shared/cplusplus/CheckExpression.cpp
+++ b/src/shared/cplusplus/CheckExpression.cpp
@@ -289,12 +289,13 @@ bool CheckExpression::visit(ThisExpressionAST *)
 
 bool CheckExpression::visit(CompoundExpressionAST *ast)
 {
-    return true; // ###
+    _fullySpecifiedType = semantic()->check(ast->compoundStatement, _scope);
+    return false;
 }
 
 bool CheckExpression::visit(NestedExpressionAST *ast)
 {
-    FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+    _fullySpecifiedType = semantic()->check(ast->expression, _scope);
     return false;
 }
 
diff --git a/src/shared/cplusplus/CheckStatement.cpp b/src/shared/cplusplus/CheckStatement.cpp
index 41ccdf1c27a..26e4e7c835a 100644
--- a/src/shared/cplusplus/CheckStatement.cpp
+++ b/src/shared/cplusplus/CheckStatement.cpp
@@ -69,13 +69,22 @@ CheckStatement::CheckStatement(Semantic *semantic)
 CheckStatement::~CheckStatement()
 { }
 
-void CheckStatement::check(StatementAST *statement, Scope *scope)
+FullySpecifiedType CheckStatement::check(StatementAST *statement, Scope *scope)
 {
+    FullySpecifiedType previousExprType = switchExprType(FullySpecifiedType());
     Scope *previousScope = switchScope(scope);
     StatementAST *previousStatement = switchStatement(statement);
     accept(statement);
     (void) switchStatement(previousStatement);
     (void) switchScope(previousScope);
+    return switchExprType(previousExprType);
+}
+
+FullySpecifiedType CheckStatement::switchExprType(const FullySpecifiedType &type)
+{
+    const FullySpecifiedType &previousExprType = _exprType;
+    _exprType = type;
+    return previousExprType;
 }
 
 StatementAST *CheckStatement::switchStatement(StatementAST *statement)
@@ -94,8 +103,8 @@ Scope *CheckStatement::switchScope(Scope *scope)
 
 bool CheckStatement::visit(CaseStatementAST *ast)
 {
-    FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
-    semantic()->check(ast->statement, _scope);
+    (void) semantic()->check(ast->expression, _scope);
+    _exprType = semantic()->check(ast->statement, _scope);
     return false;
 }
 
@@ -110,7 +119,7 @@ bool CheckStatement::visit(CompoundStatementAST *ast)
     StatementAST *previousStatement = 0;
     for (StatementListAST *it = ast->statement_list; it; it = it->next) {
         StatementAST *statement = it->value;
-        semantic()->check(statement, _scope);
+        _exprType = semantic()->check(statement, _scope);
 
         if (statement && previousStatement) {
             ExpressionStatementAST *expressionStatement = statement->asExpressionStatement();
@@ -128,13 +137,15 @@ bool CheckStatement::visit(CompoundStatementAST *ast)
 bool CheckStatement::visit(DeclarationStatementAST *ast)
 {
     semantic()->check(ast->declaration, _scope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
 bool CheckStatement::visit(DoStatementAST *ast)
 {
     semantic()->check(ast->statement, _scope);
-    FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+    (void) semantic()->check(ast->expression, _scope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
@@ -142,16 +153,18 @@ bool CheckStatement::visit(ExpressionOrDeclarationStatementAST *ast)
 {
 //    translationUnit()->warning(ast->firstToken(),
 //                               "ambiguous expression or declaration statement");
-    if (ast->declaration)
+    if (ast->declaration) {
         semantic()->check(ast->declaration, _scope);
-    else
-        semantic()->check(ast->expression, _scope);
+        _exprType = FullySpecifiedType();
+    } else {
+        _exprType = semantic()->check(ast->expression, _scope);
+    }
     return false;
 }
 
 bool CheckStatement::visit(ExpressionStatementAST *ast)
 {
-    FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+    _exprType = semantic()->check(ast->expression, _scope);
     return false;
 }
 
@@ -181,13 +194,13 @@ bool CheckStatement::forEachFastEnum(unsigned firstToken,
         decl->setType(ty);
         _scope->enterSymbol(decl);
     } else {
-        FullySpecifiedType exprTy = semantic()->check(initializer, _scope);
-        (void) exprTy;
+        (void) semantic()->check(initializer, _scope);
     }
 
-    FullySpecifiedType exprTy = semantic()->check(expression, _scope);
+    (void) semantic()->check(expression, _scope);
     semantic()->check(statement, _scope);
     (void) switchScope(previousScope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
@@ -228,6 +241,7 @@ bool CheckStatement::visit(ForStatementAST *ast)
     FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
     semantic()->check(ast->statement, _scope);
     (void) switchScope(previousScope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
@@ -243,33 +257,38 @@ bool CheckStatement::visit(IfStatementAST *ast)
     semantic()->check(ast->statement, _scope);
     semantic()->check(ast->else_statement, _scope);
     (void) switchScope(previousScope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
 bool CheckStatement::visit(LabeledStatementAST *ast)
 {
     semantic()->check(ast->statement, _scope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
 bool CheckStatement::visit(BreakStatementAST *)
 {
+    _exprType = FullySpecifiedType();
     return false;
 }
 
 bool CheckStatement::visit(ContinueStatementAST *)
 {
+    _exprType = FullySpecifiedType();
     return false;
 }
 
 bool CheckStatement::visit(GotoStatementAST *)
 {
+    _exprType = FullySpecifiedType();
     return false;
 }
 
 bool CheckStatement::visit(ReturnStatementAST *ast)
 {
-    FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope);
+    _exprType = semantic()->check(ast->expression, _scope);
     return false;
 }
 
@@ -284,6 +303,7 @@ bool CheckStatement::visit(SwitchStatementAST *ast)
     FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
     semantic()->check(ast->statement, _scope);
     (void) switchScope(previousScope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
@@ -293,6 +313,7 @@ bool CheckStatement::visit(TryBlockStatementAST *ast)
     for (CatchClauseListAST *it = ast->catch_clause_list; it; it = it->next) {
         semantic()->check(it->value, _scope);
     }
+    _exprType = FullySpecifiedType();
     return false;
 }
 
@@ -307,6 +328,7 @@ bool CheckStatement::visit(CatchClauseAST *ast)
     semantic()->check(ast->exception_declaration, _scope);
     semantic()->check(ast->statement, _scope);
     (void) switchScope(previousScope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
@@ -321,6 +343,7 @@ bool CheckStatement::visit(WhileStatementAST *ast)
     FullySpecifiedType condTy = semantic()->check(ast->condition, _scope);
     semantic()->check(ast->statement, _scope);
     (void) switchScope(previousScope);
+    _exprType = FullySpecifiedType();
     return false;
 }
 
@@ -353,6 +376,6 @@ bool CheckStatement::visit(QtMemberDeclarationAST *ast)
     symbol->setType(control()->pointerType(declTy));
 
     _scope->enterSymbol(symbol);
-
+    _exprType = FullySpecifiedType();
     return false;
 }
diff --git a/src/shared/cplusplus/CheckStatement.h b/src/shared/cplusplus/CheckStatement.h
index 5c1b1ff02d8..dc8447f37e4 100644
--- a/src/shared/cplusplus/CheckStatement.h
+++ b/src/shared/cplusplus/CheckStatement.h
@@ -50,9 +50,9 @@
 #define CPLUSPLUS_CHECKSTATEMENT_H
 
 #include "CPlusPlusForwardDeclarations.h"
+#include "FullySpecifiedType.h"
 #include "SemanticCheck.h"
 
-
 namespace CPlusPlus {
 
 class CPLUSPLUS_EXPORT CheckStatement: public SemanticCheck
@@ -61,9 +61,10 @@ public:
     CheckStatement(Semantic *semantic);
     virtual ~CheckStatement();
 
-    void check(StatementAST *statement, Scope *scope);
+    FullySpecifiedType check(StatementAST *statement, Scope *scope);
 
 protected:
+    FullySpecifiedType switchExprType(const FullySpecifiedType &type);
     StatementAST *switchStatement(StatementAST *statement);
     Scope *switchScope(Scope *scope);
 
@@ -98,9 +99,12 @@ protected:
                          ExpressionAST *expression,
                          StatementAST *statement,
                          Block *&symbol);
+    FullySpecifiedType checkCompoundStmt(CompoundStatementAST *stmt);
+
 private:
     StatementAST *_statement;
     Scope *_scope;
+    FullySpecifiedType _exprType;
 };
 
 } // end of namespace CPlusPlus
diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp
index 84a92a186aa..864ec779ab4 100644
--- a/src/shared/cplusplus/Parser.cpp
+++ b/src/shared/cplusplus/Parser.cpp
@@ -3446,6 +3446,14 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node)
             ast->compoundStatement = statement->asCompoundStatement();
             match(T_RPAREN, &ast->rparen_token);
             node = ast;
+            if (ast->compoundStatement && ast->compoundStatement->statement_list) {
+                // check that the last statement is an expression-statement
+                StatementAST *lastStmt = ast->compoundStatement->statement_list->lastValue();
+                if (!lastStmt || ! ast->asExpressionStatement())
+                    _translationUnit->error(cursor(),
+                                            "expected an expression statement before token `%s'",
+                                            tok().spell());
+            }
             return true;
         } else {
             return parseNestedExpression(node);
diff --git a/src/shared/cplusplus/Semantic.cpp b/src/shared/cplusplus/Semantic.cpp
index 57ac5fe99f3..d8d6d6617e9 100644
--- a/src/shared/cplusplus/Semantic.cpp
+++ b/src/shared/cplusplus/Semantic.cpp
@@ -151,8 +151,8 @@ void Semantic::check(ObjCMessageArgumentDeclarationAST *arg, Scope *scope)
 FullySpecifiedType Semantic::check(ExpressionAST *expression, Scope *scope)
 { return d->checkExpression->check(expression, scope); }
 
-void Semantic::check(StatementAST *statement, Scope *scope)
-{ d->checkStatement->check(statement, scope); }
+FullySpecifiedType Semantic::check(StatementAST *statement, Scope *scope)
+{ return d->checkStatement->check(statement, scope); }
 
 const Name *Semantic::check(NameAST *name, Scope *scope)
 { return d->checkName->check(name, scope); }
diff --git a/src/shared/cplusplus/Semantic.h b/src/shared/cplusplus/Semantic.h
index 98c64505203..60f82b892e0 100644
--- a/src/shared/cplusplus/Semantic.h
+++ b/src/shared/cplusplus/Semantic.h
@@ -81,7 +81,7 @@ public:
 
     void check(DeclarationAST *declaration, Scope *scope, TemplateParameters *templateParameters = 0);
 
-    void check(StatementAST *statement, Scope *scope);
+    FullySpecifiedType check(StatementAST *statement, Scope *scope);
 
     const Name *check(NameAST *name, Scope *scope);
 
-- 
GitLab