From 5e8c3f4be721d2fd9f765d37b4ee0f3075a3c198 Mon Sep 17 00:00:00 2001
From: Francois Ferrand <thetypz@gmail.com>
Date: Fri, 4 Jan 2013 10:55:44 +0100
Subject: [PATCH] C++: fix constructor definition parsing.

When a constructor is defined with a single, unnamed argument of a custom type without
extra type specifiers (const...), then the constructor was not identified as such.
There was an heuristic in case the constructor was in the class definition, but not if the
the constructor was defined later.

Examples:

class Arg;
class Other;

class Foo {
  Foo(Arg /*arg*/);               // working
  Foo(const Arg /*arg*/);         // working
  Foo(int /*arg*/);               // working
  Foo(Other /*arg*/)         {}   // working
};

Foo::Foo(Arg /*arg*/)        {}   // used not to work, fixed
Foo::Foo(Arg arg){}               // working
Foo::Foo(const Arg /*arg*/)  {}   // working
Foo::Foo(int arg)            {}   // working

Change-Id: I741e4ba62672ddc99a837fdcdc27996fba5ae6c7
Reviewed-by: hjk <qthjk@ovi.com>
---
 src/libs/3rdparty/cplusplus/Parser.cpp |  17 ++-
 tests/auto/cplusplus/ast/tst_ast.cpp   | 154 +++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 6 deletions(-)

diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp
index dc9448cd723..02eddeb8ba2 100644
--- a/src/libs/3rdparty/cplusplus/Parser.cpp
+++ b/src/libs/3rdparty/cplusplus/Parser.cpp
@@ -3904,12 +3904,17 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, ClassSpecifierAST *de
             startOfNamedTypeSpecifier = cursor();
             if (parseName(named_type_specifier)) {
 
-              if (LA() == T_LPAREN && identifier(named_type_specifier) == className(declaringClass)) {
-                // looks like a constructor declaration
-                rewind(startOfNamedTypeSpecifier);
-                break;
-              }
-
+                const Identifier *classIdentifier = className(declaringClass);
+                if (QualifiedNameAST *qn = named_type_specifier->asQualifiedName())
+                    if (NestedNameSpecifierListAST *namesList = qn->nested_name_specifier_list)
+                        if (NestedNameSpecifierAST *lastName = namesList->lastValue())
+                            classIdentifier = identifier(lastName->class_or_namespace_name);
+
+                if (LA() == T_LPAREN && identifier(named_type_specifier) == classIdentifier) {
+                    // looks like a constructor declaration
+                    rewind(startOfNamedTypeSpecifier);
+                    break;
+                }
 
                 NamedTypeSpecifierAST *spec = new (_pool) NamedTypeSpecifierAST;
                 spec->name = named_type_specifier;
diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp
index 0afa5e25329..33be7a677e5 100644
--- a/tests/auto/cplusplus/ast/tst_ast.cpp
+++ b/tests/auto/cplusplus/ast/tst_ast.cpp
@@ -136,6 +136,16 @@ private slots:
     void assignment_1();
     void assignment_2();
 
+    // constructor declarations
+    void cpp_constructor_one_unamed_arg();
+    void cpp_constructor_one_unamed_arg_namespace();
+    void cpp_constructor_one_knowntype_arg();
+    void cpp_constructor_one_const_arg();
+    void cpp_constructor_one_ref_arg();
+    void cpp_constructor_one_named_arg();
+    void cpp_constructor_no_arg();
+    void cpp_constructor_multiple_args();
+
     // objc++
     void objc_simple_class();
     void objc_attributes_followed_by_at_keyword();
@@ -1050,6 +1060,150 @@ void tst_AST::cpp_initializer_or_function_declaration()
     QCOMPARE(param->type_specifier_list->value->asNamedTypeSpecifier()->name->asSimpleName()->identifier_token, 4U);
 }
 
+void tst_AST::cpp_constructor_one_unamed_arg()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo(QString /*name*/) {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause != 0);
+    QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
+}
+
+void tst_AST::cpp_constructor_one_unamed_arg_namespace()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("Foo::QFileInfo::QFileInfo(QString /*name*/) {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause != 0);
+    QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
+}
+
+void tst_AST::cpp_constructor_one_named_arg()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo(QString name) {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause != 0);
+    QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
+}
+
+void tst_AST::cpp_constructor_one_knowntype_arg()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo(int /*name*/) {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause != 0);
+    QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
+}
+
+
+void tst_AST::cpp_constructor_one_const_arg()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo(const QString /*name*/) {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause != 0);
+    QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
+}
+
+void tst_AST::cpp_constructor_one_ref_arg()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo(QString & /*name*/) {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause != 0);
+    QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
+}
+
+void tst_AST::cpp_constructor_no_arg()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo() {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause == 0);
+}
+
+void tst_AST::cpp_constructor_multiple_args()
+{
+    QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo(QString /*name*/, QString /*type*/) {}"));
+    AST *ast = unit->ast();
+    QVERIFY(ast != 0);
+
+    FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
+    QVERIFY(funDef != 0);
+    QVERIFY(funDef->declarator != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list != 0);
+    QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
+
+    FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
+    QVERIFY(funDecl != 0);
+    QVERIFY(funDecl->parameter_declaration_clause != 0);
+    QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
+}
+
 void tst_AST::objc_simple_class()
 {
     QSharedPointer<TranslationUnit> unit(parseDeclaration("\n"
-- 
GitLab