diff --git a/languages/cpp/cppduchain/CMakeLists.txt b/languages/cpp/cppduchain/CMakeLists.txt index 7eba67f..5f27b8f 100644 --- a/languages/cpp/cppduchain/CMakeLists.txt +++ b/languages/cpp/cppduchain/CMakeLists.txt @@ -26,6 +26,7 @@ set(kdevcppduchain_LIB_SRCS cppeditorintegrator.cpp dumpchain.cpp cpptypes.cpp + ptrtomembertype.cpp dumptypes.cpp environmentmanager.cpp cppduchain.cpp diff --git a/languages/cpp/cppduchain/cpptypes.h b/languages/cpp/cppduchain/cpptypes.h index 87645e9..ccf4848 100644 --- a/languages/cpp/cppduchain/cpptypes.h +++ b/languages/cpp/cppduchain/cpptypes.h @@ -36,6 +36,7 @@ #include "cppduchainexport.h" #include #include +#include "ptrtomembertype.h" namespace KDevelop { diff --git a/languages/cpp/cppduchain/expressionvisitor.cpp b/languages/cpp/cppduchain/expressionvisitor.cpp index 7e73477..40290b0 100644 --- a/languages/cpp/cppduchain/expressionvisitor.cpp +++ b/languages/cpp/cppduchain/expressionvisitor.cpp @@ -1178,6 +1178,8 @@ void ExpressionVisitor::createDelayedType( AST* node , bool expression ) { if(fail || !constructedType) { DefaultVisitor::visitInitDeclarator(node); return; + } else { + visitNodes(this,node->declarator->ptr_ops); } DeclarationPointer chosenFunction; @@ -1225,7 +1227,7 @@ void ExpressionVisitor::createDelayedType( AST* node , bool expression ) { visit(node->parameter_declaration_clause); visit(node->exception_spec); - + { LOCKDUCHAIN; if( node->array_dimensions && oldLastType ) { ArrayType::Ptr p( new ArrayType() ); @@ -1237,7 +1239,7 @@ void ExpressionVisitor::createDelayedType( AST* node , bool expression ) { m_lastType = oldLastType; m_lastInstance = oldLastInstance; } - + } visitNodes(this, node->ptr_ops); } @@ -1262,7 +1264,6 @@ void ExpressionVisitor::createDelayedType( AST* node , bool expression ) { m_lastType = lastType; m_lastInstance = instance; - LOCKDUCHAIN; visit(node->ptr_op); } @@ -1294,17 +1295,22 @@ void ExpressionVisitor::createDelayedType( AST* node , bool expression ) { void ExpressionVisitor::visitPtrOperator(PtrOperatorAST* node) { PushPositiveContext pushContext( m_currentContext, node->ducontext ); - if( !m_lastType ) { + if( !m_lastType ) problem(node, "Pointer-operator used without type"); - return; - } - if( m_lastInstance ) { + if( m_lastInstance ) problem(node, "Pointer-operator used on an instance instead of a type"); - return; - } - LOCKDUCHAIN; + + ///pointer-to-member + if(node->op==0){ + PtrToMemberType::Ptr p( new PtrToMemberType() ); + p->setBaseType( m_lastType ); + p->setModifiers(TypeBuilder::parseConstVolatile(m_session, node->cv)); + visit( node->mem_ptr->class_type ); + p->setClassType( m_lastType ); + m_lastType = p.cast(); + } else { static IndexedString ref("&"); static IndexedString ptr("*"); @@ -1326,6 +1332,7 @@ void ExpressionVisitor::createDelayedType( AST* node , bool expression ) { m_lastType = p.cast(); } + } m_lastInstance = Instance(false); } diff --git a/languages/cpp/cppduchain/tests/test_duchain.cpp b/languages/cpp/cppduchain/tests/test_duchain.cpp index 327e6d0..0f24a53 100644 --- a/languages/cpp/cppduchain/tests/test_duchain.cpp +++ b/languages/cpp/cppduchain/tests/test_duchain.cpp @@ -499,6 +499,7 @@ void TestDUChain::testIntegralTypes() //Even if reference/pointer types have an invalid target, they should still preserve the pointer QVERIFY(AbstractType::Ptr(new ReferenceType)->toString().endsWith("&")); QVERIFY(AbstractType::Ptr(new PointerType)->toString().endsWith("*")); + QVERIFY(AbstractType::Ptr(new PtrToMemberType)->toString().endsWith("::*")); } @@ -5861,5 +5862,69 @@ void TestDUChain::testCommentAfterFunctionCall() QVERIFY(top->childContexts().last()->localDeclarations().isEmpty()); QCOMPARE(m_view->uses().size(), 1); } +void TestDUChain::testPointerToMember() +{ + // 1 2 3 + // 123456789012345678901234567890 + LockedTopDUContext top = parse( "struct AA {" + "\n int j;" + "\n};" + "\nstruct BB{" + "\n int AA::* pj;" + "\n};" + "\nvoid f(int AA::* par){" + "\n BB b;" + "\n int AA::* BB::* ppj=&BB::pj;" + "\n b.*ppj=par;" + "\n}",DumpAll + ); + QVERIFY(top); + DUChainReadLocker lock; + QVERIFY(top->problems().isEmpty()); + QCOMPARE(top->childContexts().size(),4); + QCOMPARE(top->localDeclarations().size(),3); + + QCOMPARE(top->localDeclarations().at(0)->uses().begin()->size(),3); + QCOMPARE(top->localDeclarations().at(1)->uses().begin()->size(),3); + + QCOMPARE(top->localDeclarations().at(0)->uses().begin()->at(0),RangeInRevision(4,6,4,8)); + QCOMPARE(top->localDeclarations().at(0)->uses().begin()->at(1),RangeInRevision(6,11,6,13)); + QCOMPARE(top->localDeclarations().at(0)->uses().begin()->at(2),RangeInRevision(8,6,8,8)); + + QCOMPARE(top->localDeclarations().at(1)->uses().begin()->at(0),RangeInRevision(7,2,7,4)); + QCOMPARE(top->localDeclarations().at(1)->uses().begin()->at(1),RangeInRevision(8,12,8,14)); + QCOMPARE(top->localDeclarations().at(1)->uses().begin()->at(2),RangeInRevision(8,23,8,25)); + + { + DUContext* ctx = top->childContexts().at(1); + Declaration* dec = ctx->localDeclarations().first(); + PtrToMemberType::Ptr type = dec->abstractType().cast(); + QVERIFY(type); + StructureType::Ptr structType = type->classType().cast(); + QVERIFY(structType); + QCOMPARE(structType->qualifiedIdentifier().toString(), QString("AA")); + } + { + DUContext* ctx = top->childContexts().at(3); + Declaration* dec = ctx->localDeclarations().at(1); + PtrToMemberType::Ptr type = dec->abstractType().cast(); + + { + QVERIFY(type); + StructureType::Ptr structType = type->classType().cast(); + QVERIFY(structType); + QCOMPARE(structType->qualifiedIdentifier().toString(), QString("BB")); + } + + PtrToMemberType::Ptr ptype = type->baseType().cast(); + { + QVERIFY(ptype); + StructureType::Ptr structType = ptype->classType().cast(); + QVERIFY(structType); + QCOMPARE(structType->qualifiedIdentifier().toString(), QString("AA")); + } + } + +} #include "test_duchain.moc" diff --git a/languages/cpp/cppduchain/tests/test_duchain.h b/languages/cpp/cppduchain/tests/test_duchain.h index 4cd7d05..23efbb0 100644 --- a/languages/cpp/cppduchain/tests/test_duchain.h +++ b/languages/cpp/cppduchain/tests/test_duchain.h @@ -190,6 +190,7 @@ private slots: void testAutoTypes(); void testCommentAfterFunctionCall(); + void testPointerToMember(); private: void assertNoMemberFunctionModifiers(KDevelop::ClassFunctionDeclaration* memberFun); diff --git a/languages/cpp/cppduchain/type_visitor.cpp b/languages/cpp/cppduchain/type_visitor.cpp index cf00e6c..c49baf0 100644 --- a/languages/cpp/cppduchain/type_visitor.cpp +++ b/languages/cpp/cppduchain/type_visitor.cpp @@ -58,7 +58,8 @@ void TypeASTVisitor::run(TypeIdAST *node) do { PtrOperatorAST* ptrOp = it->element; - if (ptrOp && ptrOp->op) { ///@todo check ordering, eventually walk the chain in reversed order + if (ptrOp){ + if(ptrOp->op) { ///@todo check ordering, eventually walk the chain in reversed order IndexedString op = m_session->token_stream->token(ptrOp->op).symbol(); static IndexedString ref("&"); static IndexedString ptr("*"); @@ -75,6 +76,15 @@ void TypeASTVisitor::run(TypeIdAST *node) m_type = pointer.cast(); } } + } else{ ///ptr-to-member + PtrToMemberType::Ptr pointer(new PtrToMemberType); + pointer->setModifiers(TypeBuilder::parseConstVolatile(m_session, ptrOp->cv)); + pointer->setBaseType(m_type); + PtrToMemberAST * ast=ptrOp->mem_ptr; + visit(ast); + pointer->setClassType(m_type); + m_type=pointer.cast(); + } } it = it->next; } diff --git a/languages/cpp/cppduchain/typebuilder.cpp b/languages/cpp/cppduchain/typebuilder.cpp index 73723b2..994cc3d 100644 --- a/languages/cpp/cppduchain/typebuilder.cpp +++ b/languages/cpp/cppduchain/typebuilder.cpp @@ -594,6 +594,16 @@ void TypeBuilder::visitPtrOperator(PtrOperatorAST* node) closeType(); } +void TypeBuilder::visitPtrToMember(PtrToMemberAST *node) +{ + PtrToMemberType::Ptr pointer(new PtrToMemberType); + pointer->setBaseType(lastType()); + ContextBuilder::visitPtrToMember(node); + pointer->setClassType(lastType()); + openType(pointer); + closeType(); +} + FunctionType* TypeBuilder::openFunction(DeclaratorAST *node) { FunctionType* functionType = new FunctionType(); diff --git a/languages/cpp/cppduchain/typebuilder.h b/languages/cpp/cppduchain/typebuilder.h index 7fff507..b81c853 100644 --- a/languages/cpp/cppduchain/typebuilder.h +++ b/languages/cpp/cppduchain/typebuilder.h @@ -60,6 +60,7 @@ protected: virtual void visitTypedef(TypedefAST*); virtual void visitFunctionDeclaration(FunctionDefinitionAST*); virtual void visitPtrOperator(PtrOperatorAST*); + virtual void visitPtrToMember(PtrToMemberAST*); virtual void visitUsing(UsingAST *); virtual void visitParameterDeclaration(ParameterDeclarationAST*); virtual void visitTemplateParameter(TemplateParameterAST *); diff --git a/languages/cpp/parser/ast.h b/languages/cpp/parser/ast.h index cd896f7..0281c6b 100644 --- a/languages/cpp/parser/ast.h +++ b/languages/cpp/parser/ast.h @@ -833,6 +833,8 @@ class PtrToMemberAST : public AST public: DECLARE_AST_NODE(PtrToMember) + + TypeSpecifierAST *class_type; }; class JumpStatementAST : public StatementAST diff --git a/languages/cpp/parser/codegenerator.cpp b/languages/cpp/parser/codegenerator.cpp index fcdb04c..a65b010 100644 --- a/languages/cpp/parser/codegenerator.cpp +++ b/languages/cpp/parser/codegenerator.cpp @@ -612,8 +612,7 @@ void CodeGenerator::visitPtrOperator(PtrOperatorAST* node) void CodeGenerator::visitPtrToMember(PtrToMemberAST* node) { - // TODO fix AST - Q_UNUSED(node); + visit(node->class_type); printToken(Token_scope); m_output << "*"; } diff --git a/languages/cpp/parser/default_visitor.cpp b/languages/cpp/parser/default_visitor.cpp index 3d061ff..73c66ce 100644 --- a/languages/cpp/parser/default_visitor.cpp +++ b/languages/cpp/parser/default_visitor.cpp @@ -320,9 +320,9 @@ void DefaultVisitor::visitPtrOperator(PtrOperatorAST *node) visit(node->mem_ptr); } -void DefaultVisitor::visitPtrToMember(PtrToMemberAST *) +void DefaultVisitor::visitPtrToMember(PtrToMemberAST *node) { - // nothing to do + visit(node->class_type); } void DefaultVisitor::visitReturnStatement(ReturnStatementAST *node) diff --git a/languages/cpp/parser/parser.cpp b/languages/cpp/parser/parser.cpp index 1d4c644..281ad8d 100644 --- a/languages/cpp/parser/parser.cpp +++ b/languages/cpp/parser/parser.cpp @@ -561,8 +561,11 @@ bool Parser::parseName(NameAST*& node, ParseNameAcceptTemplate acceptTemplateId) if (!ast) ast = CreateNode(session->mempool); - if (session->token_stream->lookAhead() == Token_scope) + if (session->token_stream->lookAhead() == Token_scope && + //ptr-to-member + session->token_stream->lookAhead(1) != '*') { + advance(); ast->qualified_names @@ -2637,25 +2640,11 @@ bool Parser::parseInitializerClause(InitializerClauseAST *&node) bool Parser::parsePtrToMember(PtrToMemberAST *&node) { -#if defined(__GNUC__) -#warning "implemente me (AST)" -#endif - uint start = session->token_stream->cursor(); - uint global_scope = 0; - if (session->token_stream->lookAhead() == Token_scope) - { - global_scope = session->token_stream->cursor(); - advance(); - } - - UnqualifiedNameAST *name = 0; - while (session->token_stream->lookAhead() == Token_identifier) - { - if (!parseUnqualifiedName(name)) - break; + TypeSpecifierAST* type_ast = 0; + if(parseTypeSpecifier(type_ast)){ if (session->token_stream->lookAhead() == Token_scope && session->token_stream->lookAhead(1) == '*') { @@ -2663,14 +2652,11 @@ bool Parser::parsePtrToMember(PtrToMemberAST *&node) advance(); PtrToMemberAST *ast = CreateNode(session->mempool); + ast->class_type=type_ast; UPDATE_POS(ast, start, _M_last_valid_token+1); node = ast; - return true; } - - if (session->token_stream->lookAhead() == Token_scope) - advance(); } rewind(start); diff --git a/languages/cpp/parser/tests/test_parser.cpp b/languages/cpp/parser/tests/test_parser.cpp index e35a804..dfb7a90 100644 --- a/languages/cpp/parser/tests/test_parser.cpp +++ b/languages/cpp/parser/tests/test_parser.cpp @@ -685,6 +685,27 @@ private slots: QVERIFY(hasKind(funcAst, AST::Kind_InitDeclarator)); } + void testPtrToMemberAst() { + pool memPool; + TranslationUnitAST* ast = parse("\nstruct AA {" + "\n int j;" + "\n};" + "\nstruct BB{" + "\n int AA::* pj;" + "\n};" + "\nvoid f(){" + "\n int AA::* BB::* ppj=&BB::pj;" + "\n}" + , &memPool); + QVERIFY(ast!=0); + QCOMPARE(ast->declarations->count(), 3); + QVERIFY(hasKind(ast,AST::Kind_PtrToMember)); + FunctionDefinitionAST* f_ast=static_cast(getAST(ast,AST::Kind_FunctionDefinition)); + QVERIFY(hasKind(f_ast,AST::Kind_PtrToMember)); + DeclaratorAST* d_ast=static_cast(getAST(f_ast->function_body,AST::Kind_Declarator)); + QCOMPARE(d_ast-> ptr_ops->count(),2); + } + void testSwitchStatement() { int problemCount = control.problems().count();