diff --git a/duchain/builders/declarationbuilder.h b/duchain/builders/declarationbuilder.h --- a/duchain/builders/declarationbuilder.h +++ b/duchain/builders/declarationbuilder.h @@ -108,6 +108,7 @@ go::GoFunctionDeclaration* declareFunction(go::IdentifierAst* id, const go::GoFunctionType::Ptr& type, DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment = {}, DUContext* bodyContext = nullptr) override; + void visitMethodDeclarationInjectContext(go::MethodDeclarationAst* node, QualifiedIdentifier const& typeIdentifier); go::GoFunctionDefinition* declareMethod(go::IdentifierAst* id, const go::GoFunctionType::Ptr& type, DUContext* paramContext, DUContext* retparamContext, const QByteArray& comment=QByteArray(), DUContext* bodyContext = nullptr, go::GoFunctionDeclaration* declaration = nullptr, const QualifiedIdentifier &identifier = {}); diff --git a/duchain/builders/declarationbuilder.cpp b/duchain/builders/declarationbuilder.cpp --- a/duchain/builders/declarationbuilder.cpp +++ b/duchain/builders/declarationbuilder.cpp @@ -250,56 +250,57 @@ } } +/** + * Write lock need to be taken before calling this method + */ +void DeclarationBuilder::visitMethodDeclarationInjectContext(go::MethodDeclarationAst* node, QualifiedIdentifier const& typeIdentifier) { + auto typeDeclaration = go::getTypeDeclaration(typeIdentifier, currentContext()); + auto toBeInjectedContext = typeDeclaration ? typeDeclaration->internalContext() : nullptr; + if(!typeDeclaration || !typeDeclaration->internalContext()) + { + openContext(node->methodName, node->methodName, DUContext::ContextType::Class, typeIdentifier); + if(typeDeclaration) + { + typeDeclaration->setInternalContext(currentContext()); + } + toBeInjectedContext = currentContext(); + closeContext(); + } + + injectContext(toBeInjectedContext); +} + void DeclarationBuilder::visitMethodDeclaration(go::MethodDeclarationAst* node) { + auto typeIdentifier = identifierForNode(go::getMethodRecvTypeIdentifier(node->methodRecv)); - go::GoFunctionDeclaration* functionDeclaration = nullptr; - QualifiedIdentifier typeIdentifier; - auto containerType = go::getMethodRecvTypeIdentifier(node->methodRecv); + DUChainWriteLocker writeLock; + visitMethodDeclarationInjectContext(node, typeIdentifier); - { - DUChainWriteLocker lock; - typeIdentifier = identifierForNode(containerType); - auto typeDeclaration = go::getTypeDeclaration(typeIdentifier, currentContext()); - auto toBeInjectedContext = typeDeclaration ? typeDeclaration->internalContext() : nullptr; - if(!typeDeclaration || !typeDeclaration->internalContext()) - { - openContext(node->methodName, node->methodName, DUContext::ContextType::Class, typeIdentifier); - if(typeDeclaration) - { - typeDeclaration->setInternalContext(currentContext()); - } - toBeInjectedContext = currentContext(); - closeContext(); - } + auto range = RangeInRevision(currentContext()->range().start, currentContext()->range().start); + auto functionDeclaration = openDeclaration(identifierForNode(node->methodName).last(), range); + functionDeclaration->setAutoDeclaration(true); + closeDeclaration(); - injectContext(toBeInjectedContext); + closeInjectedContext(); + writeLock.unlock(); - auto range = RangeInRevision(currentContext()->range().start, currentContext()->range().start); - functionDeclaration = openDeclaration(identifierForNode(node->methodName).last(), range); - functionDeclaration->setAutoDeclaration(true); - closeDeclaration(); + DUChainReadLocker readLock; + auto identifier = functionDeclaration->qualifiedIdentifier(); + readLock.unlock(); - closeInjectedContext(); - } + openContext(node, editorFindRange(node, 0), DUContext::ContextType::Class, typeIdentifier); + writeLock.lock(); - QualifiedIdentifier identifier; - { - DUChainReadLocker lock; - identifier = functionDeclaration->qualifiedIdentifier(); - } - openContext(node, editorFindRange(node, 0), DUContext::ContextType::Class, typeIdentifier); - DUChainWriteLocker lock; auto functionDefinition = buildMethod(node->signature, node->body, node->methodName, functionDeclaration, m_session->commentBeforeToken(node->startToken-1), identifier); functionDeclaration->setType(functionDefinition->type()); functionDeclaration->setKind(Declaration::Instance); - lock.unlock(); - - if(node->methodRecv->type && functionDefinition->internalContext()) + auto internalCtx = functionDefinition->internalContext(); + if(node->methodRecv->type && internalCtx) { //declare method receiver variable('this' or 'self' analog in Go) - openContext(functionDefinition->internalContext()); + openContext(internalCtx); buildTypeName(node->methodRecv->type); if(node->methodRecv->star!= -1) { @@ -307,7 +308,6 @@ ptype->setBaseType(lastType()); injectType(PointerType::Ptr(ptype)); } - DUChainWriteLocker n; functionDefinition->setDeclaration(functionDeclaration); auto methodReceiverName = node->methodRecv->nameOrType; Declaration* thisVariable = openDeclaration(identifierForNode(methodReceiverName).last(), @@ -317,6 +317,7 @@ closeContext(); } closeContext(); + writeLock.unlock(); } void DeclarationBuilder::visitTypeSpec(go::TypeSpecAst* node)