diff --git a/plugins/outlineview/outlinenode.cpp b/plugins/outlineview/outlinenode.cpp index 56730acb6f..0b4041ea00 100644 --- a/plugins/outlineview/outlinenode.cpp +++ b/plugins/outlineview/outlinenode.cpp @@ -1,196 +1,203 @@ /* * KDevelop outline view * Copyright 2010, 2015 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "outlinenode.h" #include #include #include #include #include #include #include #include #include #include #include #include "debug_outline.h" using namespace KDevelop; OutlineNode::OutlineNode(const QString& text, OutlineNode* parent) : m_cachedText(text) , m_parent(parent) { } OutlineNode::OutlineNode(Declaration* decl, OutlineNode* parent) : m_decl(decl) , m_parent(parent) { // qCDebug(PLUGIN_OUTLINE) << "Adding:" << decl->qualifiedIdentifier().toString() << ": " <identifier().toString(); m_cachedIcon = DUChainUtils::iconForDeclaration(decl); if (NamespaceAliasDeclaration* alias = dynamic_cast(decl)) { //e.g. C++ using namespace statement m_cachedText = alias->importIdentifier().toString(); } else if (ClassMemberDeclaration* member = dynamic_cast(decl)) { if (member->isFriend()) { m_cachedText = "friend " + m_cachedText; } } if (AbstractType::Ptr type = decl->abstractType()) { //add the (function return) type at the end (after a colon - like UML) //so that the first thing seen is the name of the function/variable //and not the (function return) type AbstractType::WhichType typeEnum = type->whichType(); switch (typeEnum) { case AbstractType::TypeFunction: { FunctionType::Ptr func = type.cast(); // func->partToString() does not add the argument names -> do it manually if (DUContext* fCtx = DUChainUtils::getFunctionContext(decl)) { m_cachedText += '('; bool first = true; foreach (Declaration* childDecl, fCtx->localDeclarations(decl->topContext())) { if (first) { first = false; } else { m_cachedText += QStringLiteral(", "); } m_cachedText += childDecl->abstractType()->toString(); auto ident = childDecl->identifier(); if (!ident.isEmpty()) { m_cachedText += ' ' + ident.toString(); } } m_cachedText += ')'; } else { qCWarning(PLUGIN_OUTLINE) << "Missing function context:" << decl->qualifiedIdentifier().toString(); m_cachedText += func->partToString(FunctionType::SignatureArguments); } //constructors/destructors have no return type, a trailing semicolon would look stupid if (func->returnType()) { m_cachedText += " : " + func->partToString(FunctionType::SignatureReturn); } return; // don't append any children here! } case AbstractType::TypeEnumeration: //no need to append the fully qualified type break; case AbstractType::TypeEnumerator: //no need to append the fully qualified type Q_ASSERT(decl->type()); m_cachedText += " = " + decl->type()->valueAsString(); break; case AbstractType::TypeStructure: { //this seems to be the way it has to be done (after grepping through source code) //TODO shouldn't there be some kind of isFriend() functionality? static IndexedIdentifier friendIdentifier(Identifier("friend")); const bool isFriend = decl->indexedIdentifier() == friendIdentifier; if (isFriend) { //FIXME There seems to be no way of finding out whether the friend is class/struct/etc m_cachedText += ' ' + type->toString(); } break; } case AbstractType::TypeAlias: { //append the type it aliases TypeAliasType::Ptr alias = type.cast(); if (AbstractType::Ptr targetType = alias->type()) { m_cachedText += " : " + targetType->toString(); } } break; default: QString typeStr = type->toString(); if (!typeStr.isEmpty()) { m_cachedText += " : " + typeStr; } } } //these two don't seem to be hit if (decl->isAutoDeclaration()) { m_cachedText = "Implicit: " + m_cachedText; } if (decl->isAnonymous()) { m_cachedText = "" + m_cachedText; } if (DUContext* ctx = decl->internalContext()) { appendContext(ctx, decl->topContext()); } if (m_cachedText.isEmpty()) { m_cachedText = i18nc("An anonymous declaration (class, function, etc.)", ""); } } inline std::unique_ptr OutlineNode::dummyNode() { return std::unique_ptr(new OutlineNode(QStringLiteral(""), nullptr)); } std::unique_ptr OutlineNode::fromTopContext(TopDUContext* ctx) { auto result = dummyNode(); result->appendContext(ctx, ctx); return result; } void OutlineNode::appendContext(DUContext* ctx, TopDUContext* top) { qDebug() << ctx->scopeIdentifier().toString() << "context type=" << ctx->type(); foreach (Declaration* childDecl, ctx->localDeclarations(top)) { if (childDecl) { m_children.emplace_back(childDecl, this); } } - if (ctx->type() != DUContext::Template) { - return; //no need to list these subcontexts - } foreach (DUContext* childContext, ctx->childContexts()) { - if (!childContext) + Declaration* owner = childContext->owner(); + if (owner) { + // qDebug() << childContext->scopeIdentifier(true).toString() + // << " has an owner declaration: " << owner->toString() << "-> skip"; continue; + } QVector decls = childContext->localDeclarations(top); if (decls.isEmpty()) { continue; } QString ctxName = childContext->scopeIdentifier(true).toString(); // if child context is a template context or if name is empty append to current list, // otherwise create a new context node - OutlineNode* childNode = 0; if (childContext->type() == DUContext::Template || ctxName.isEmpty()) { - childNode = this; + //append all subcontexts to this node + appendContext(childContext, top); } else { + // context without matching declaration, for example the definition of + // "class Foo::Bar if it was forward declared in a namespace before: + // namespace Foo { class Bar; } + // class Foo::Bar { ... }; + // TODO: icon and location for the namespace m_children.emplace_back(ctxName, this); + foreach (DUContext* d, childContext->childContexts()) { + m_children.back().appendContext(d, top); + } } - //append all subcontexts recursively - childNode->appendContext(childContext, top); } } OutlineNode::~OutlineNode() { }