diff --git a/codecompletion/items/functionitem.cpp b/codecompletion/items/functionitem.cpp --- a/codecompletion/items/functionitem.cpp +++ b/codecompletion/items/functionitem.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "types/gofunctiontype.h" #include "declarations/functiondeclaration.h" @@ -42,9 +43,12 @@ if(type->modifiers() == go::GoFunctionType::VariadicArgument) variadicArgs = true; - DUContext* argsContext = 0; + DUContext* argsContext = nullptr; if(function) - argsContext = function->internalContext(); + { + DUChainReadLocker lock; + argsContext = DUChainUtils::getArgumentContext(function.data()); + } m_arguments = "("; if(argsContext) { diff --git a/duchain/builders/declarationbuilder.h b/duchain/builders/declarationbuilder.h --- a/duchain/builders/declarationbuilder.h +++ b/duchain/builders/declarationbuilder.h @@ -64,7 +64,11 @@ virtual void visitCommClause(go::CommClauseAst* node); virtual void visitTypeDecl(go::TypeDeclAst* node); - + + /** + * A shortcut for ExpressionVisitor to build function type + **/ + go::GoFunctionDeclaration* buildFunction(go::SignatureAst* node, go::BlockAst* block = nullptr, go::IdentifierAst* name = nullptr, const QByteArray& comment = {}); /*struct GoImport{ GoImport(bool anon, KDevelop::TopDUContext* ctx) : anonymous(anon), context(ctx) {} @@ -98,7 +102,7 @@ * Called from typebuilder when building functions and methods **/ virtual go::GoFunctionDeclaration* declareFunction(go::IdentifierAst* id, const go::GoFunctionType::Ptr& type, - DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment=QByteArray()) override; + DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment = {}, DUContext* bodyContext = nullptr) override; void importThisPackage(); void importBuiltins(); diff --git a/duchain/builders/declarationbuilder.cpp b/duchain/builders/declarationbuilder.cpp --- a/duchain/builders/declarationbuilder.cpp +++ b/duchain/builders/declarationbuilder.cpp @@ -230,28 +230,7 @@ void DeclarationBuilder::visitFuncDeclaration(go::FuncDeclarationAst* node) { - go::GoFunctionDeclaration* decl = parseSignature(node->signature, true, node->funcName, m_session->commentBeforeToken(node->startToken-1)); - if(!node->body) - return; - //a context will be opened when visiting block, but we still open another one here - //so we can import arguments into it.(same goes for methodDeclaration) - DUContext* bodyContext = openContext(node->body, DUContext::ContextType::Function, node->funcName); - {//import parameters into body context - DUChainWriteLocker lock; - if(decl->internalContext()) - currentContext()->addImportedParentContext(decl->internalContext()); - if(decl->returnArgsContext()) - currentContext()->addImportedParentContext(decl->returnArgsContext()); - } - - visitBlock(node->body); - { - DUChainWriteLocker lock; - lastContext()->setType(DUContext::Function); - decl->setInternalFunctionContext(lastContext()); //inner block context - decl->setKind(Declaration::Instance); - } - closeContext(); //body wrapper context + buildFunction(node->signature, node->body, node->funcName, m_session->commentBeforeToken(node->startToken-1)); } void DeclarationBuilder::visitPrimaryExpr(go::PrimaryExprAst *node) @@ -271,58 +250,39 @@ Declaration* declaration=0; if(node->methodRecv) { - go::IdentifierAst* actualtype=0; - if(node->methodRecv->ptype) - actualtype = node->methodRecv->ptype; - else if(node->methodRecv->type) - actualtype = node->methodRecv->type; - else - actualtype = node->methodRecv->nameOrType; - DUChainWriteLocker lock; - declaration = openDeclaration(identifierForNode(actualtype), editorFindRange(actualtype, 0)); - declaration->setKind(Declaration::Namespace); - openContext(node, editorFindRange(node, 0), DUContext::Namespace, identifierForNode(actualtype)); - declaration->setInternalContext(currentContext()); + go::IdentifierAst* actualtype=0; + if(node->methodRecv->ptype) + actualtype = node->methodRecv->ptype; + else if(node->methodRecv->type) + actualtype = node->methodRecv->type; + else + actualtype = node->methodRecv->nameOrType; + DUChainWriteLocker lock; + declaration = openDeclaration(identifierForNode(actualtype), editorFindRange(actualtype, 0)); + declaration->setKind(Declaration::Namespace); + openContext(node, editorFindRange(node, 0), DUContext::Namespace, identifierForNode(actualtype)); + declaration->setInternalContext(currentContext()); } - go::GoFunctionDeclaration* decl = parseSignature(node->signature, true, node->methodName, m_session->commentBeforeToken(node->startToken-1)); - - if(!node->body) - return; - DUContext* bodyContext = openContext(node->body, DUContext::ContextType::Function, node->methodName); + auto functionDeclaration = buildFunction(node->signature, node->body, node->methodName, m_session->commentBeforeToken(node->startToken-1)); - {//import parameters into body context - DUChainWriteLocker lock; - if(decl->internalContext()) - currentContext()->addImportedParentContext(decl->internalContext()); - if(decl->returnArgsContext()) - currentContext()->addImportedParentContext(decl->returnArgsContext()); - } - - if(node->methodRecv->type) + if(node->methodRecv->type && functionDeclaration->internalContext()) {//declare method receiver variable('this' or 'self' analog in Go) + openContext(functionDeclaration->internalContext()); buildTypeName(node->methodRecv->type); - if(node->methodRecv->star!= -1) - { - PointerType* ptype = new PointerType(); - ptype->setBaseType(lastType()); - injectType(PointerType::Ptr(ptype)); - } - DUChainWriteLocker n; - Declaration* thisVariable = openDeclaration(identifierForNode(node->methodRecv->nameOrType), editorFindRange(node->methodRecv->nameOrType, 0)); - thisVariable->setAbstractType(lastType()); - closeDeclaration(); - } - - visitBlock(node->body); - { - DUChainWriteLocker lock; - lastContext()->setType(DUContext::Function); - decl->setInternalFunctionContext(lastContext()); //inner block context - decl->setKind(Declaration::Instance); + if(node->methodRecv->star!= -1) + { + PointerType* ptype = new PointerType(); + ptype->setBaseType(lastType()); + injectType(PointerType::Ptr(ptype)); + } + DUChainWriteLocker n; + Declaration* thisVariable = openDeclaration(identifierForNode(node->methodRecv->nameOrType), editorFindRange(node->methodRecv->nameOrType, 0)); + thisVariable->setAbstractType(lastType()); + closeDeclaration(); + closeContext(); } - - closeContext(); //body wrapper context + closeContext(); //namespace closeDeclaration(); //namespace declaration } @@ -608,19 +568,40 @@ go::GoFunctionDeclaration* DeclarationBuilder::declareFunction(go::IdentifierAst* id, const go::GoFunctionType::Ptr& type, - DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment) + DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment, DUContext* bodyContext) { setComment(comment); DUChainWriteLocker lock; go::GoFunctionDeclaration* dec = openDefinition(identifierForNode(id), editorFindRange(id, 0)); dec->setType(type); - //dec->setKind(Declaration::Type); dec->setKind(Declaration::Instance); - dec->setInternalContext(paramContext); - if(retparamContext) - dec->setReturnArgsContext(retparamContext); - //dec->setInternalFunctionContext(bodyContext); + dec->setInternalContext(bodyContext); + + if(bodyContext) + { + if(paramContext) + { + bodyContext->addImportedParentContext(paramContext); + dec->setInternalFunctionContext(paramContext); + } + if(retparamContext) + { + bodyContext->addImportedParentContext(retparamContext); + dec->setReturnArgsContext(retparamContext); + } + } + closeDeclaration(); return dec; } +go::GoFunctionDeclaration* DeclarationBuilder::buildFunction(go::SignatureAst* node, go::BlockAst* block, go::IdentifierAst* name, const QByteArray& comment) +{ + DUContext* bodyContext = nullptr; + if(block) + { + visitBlock(block); + bodyContext = lastContext(); + } + return parseSignature(node, true, bodyContext, name, comment); +} \ No newline at end of file diff --git a/duchain/builders/typebuilder.h b/duchain/builders/typebuilder.h --- a/duchain/builders/typebuilder.h +++ b/duchain/builders/typebuilder.h @@ -52,11 +52,6 @@ void buildTypeName(go::IdentifierAst* typeName, go::IdentifierAst* fullName = 0); /** - * A shortcut for ExpressionVisitor to build function type - **/ - void buildFunction(go::SignatureAst* node, go::BlockAst* block=0); - - /** * Used by external classes like ExpressionVisitor after building a type. */ AbstractType::Ptr getLastType() { return lastType(); } @@ -76,14 +71,12 @@ * declared here as pure virtual so we can use that when building functions **/ virtual GoFunctionDeclaration* declareFunction(go::IdentifierAst* id, const GoFunctionType::Ptr& type, - DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment=QByteArray()) = 0; - - + DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment=QByteArray(), DUContext* bodyContext = nullptr) = 0; /** * opens GoFunctionType, parses it's parameters and return declaration if @param declareParameters is true. **/ - go::GoFunctionDeclaration* parseSignature(go::SignatureAst* node, bool declareParameters, go::IdentifierAst* name=0, const QByteArray& comment=QByteArray()); + go::GoFunctionDeclaration* parseSignature(go::SignatureAst* node, bool declareParameters, DUContext* bodyContext = nullptr, go::IdentifierAst* name=0, const QByteArray& comment=QByteArray()); /** * Convenience function that parses function parameters. diff --git a/duchain/builders/typebuilder.cpp b/duchain/builders/typebuilder.cpp --- a/duchain/builders/typebuilder.cpp +++ b/duchain/builders/typebuilder.cpp @@ -228,7 +228,7 @@ { if(node->signature) { - parseSignature(node->signature, true, node->methodName); + parseSignature(node->signature, true, nullptr, node->methodName); }else{ buildTypeName(node->methodName, node->fullName); go::IdentifierAst* id = node->fullName ? node->fullName : node->methodName; @@ -281,21 +281,21 @@ } -go::GoFunctionDeclaration* TypeBuilder::parseSignature(go::SignatureAst* node, bool declareParameters, go::IdentifierAst* name, const QByteArray& comment) +go::GoFunctionDeclaration* TypeBuilder::parseSignature(go::SignatureAst* node, bool declareParameters, DUContext* bodyContext, go::IdentifierAst* name, const QByteArray& comment) { go::GoFunctionType::Ptr type(new go::GoFunctionType()); openType(type); - DUContext* parametersContext; + DUContext* parametersContext = nullptr; if(declareParameters) parametersContext = openContext(node->parameters, editorFindRange(node->parameters, 0), DUContext::ContextType::Function, name); parseParameters(node->parameters, true, declareParameters); if(declareParameters) closeContext(); - DUContext* returnArgsContext=0; + DUContext* returnArgsContext = nullptr; if(node->result) { @@ -317,7 +317,7 @@ if(declareParameters) { - return declareFunction(name, type, parametersContext, returnArgsContext, comment); + return declareFunction(name, type, parametersContext, returnArgsContext, comment, bodyContext); } return 0; } @@ -428,26 +428,4 @@ } } -//TODO call this from DeclarationBuilder::visitFunctionDecl -void TypeBuilder::buildFunction(SignatureAst* node, BlockAst* block) -{ - go::GoFunctionDeclaration* decl = parseSignature(node, true); - AbstractType::Ptr type = lastType(); - if(block) - { - DUContext* bodyContext = openContext(block, DUContext::ContextType::Function); - {//import parameters into body context - DUChainWriteLocker lock; - if(decl->internalContext()) - currentContext()->addImportedParentContext(decl->internalContext()); - if(decl->returnArgsContext()) - currentContext()->addImportedParentContext(decl->returnArgsContext()); - } - visitBlock(block); - closeContext(); //wrapper context - injectType(type); - } -} - - } \ No newline at end of file diff --git a/duchain/tests/testduchain.cpp b/duchain/tests/testduchain.cpp --- a/duchain/tests/testduchain.cpp +++ b/duchain/tests/testduchain.cpp @@ -345,10 +345,10 @@ DUChainReadLocker lock; auto decls = context->findDeclarations(QualifiedIdentifier("mytype::main")); QCOMPARE(decls.size(), 1); - AbstractFunctionDeclaration* function = dynamic_cast(decls.first()); + auto function = dynamic_cast(decls.first()); QVERIFY(function); - context = function->internalFunctionContext(); - QCOMPARE(context->localDeclarations().size(), 1); + context = function->internalContext(); + QCOMPARE(context->localDeclarations().size(), 2); QCOMPARE(context->findDeclarations(QualifiedIdentifier("i")).size(), 1); QCOMPARE(context->findDeclarations(QualifiedIdentifier("a")).size(), 1); QCOMPARE(context->findDeclarations(QualifiedIdentifier("b")).size(), 1); @@ -640,7 +640,7 @@ DUChainReadLocker lock; QCOMPARE(context->usesCount(), 1); - QCOMPARE(context->uses()->usedDeclaration(context->topContext()), context->parentContext()->parentContext()->localDeclarations().at(1)); + QCOMPARE(context->uses()->usedDeclaration(context->topContext()), context->parentContext()->localDeclarations().at(1)); } void TestDuchain::test_functionContextIsCreatedWhenDeclaringAsMemberOfStruct_data() @@ -717,10 +717,10 @@ auto decls = packageContext->findDeclarations(QualifiedIdentifier("main")); if(decls.size() == 0) return 0; - AbstractFunctionDeclaration* function = dynamic_cast(decls.first()); + auto function = dynamic_cast(decls.first()); if(!function) return 0; - return function->internalFunctionContext(); + return function->internalContext(); } DUContext* getMainContext(const QString& code)