diff --git a/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp b/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp
index bbb3b8f1b2..4940736c68 100644
--- a/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp
+++ b/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp
@@ -1,891 +1,891 @@
/*
Copyright 2007 David Nolden
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "abstractdeclarationnavigationcontext.h"
#include
#include
#include "../functiondeclaration.h"
#include "../functiondefinition.h"
#include "../classfunctiondeclaration.h"
#include "../namespacealiasdeclaration.h"
#include "../forwarddeclaration.h"
#include "../types/enumeratortype.h"
#include "../types/enumerationtype.h"
#include "../types/functiontype.h"
#include "../duchainutils.h"
#include "../types/pointertype.h"
#include "../types/referencetype.h"
#include "../types/typeutils.h"
#include "../types/typesystem.h"
#include "../persistentsymboltable.h"
#include
#include
#include
#include
#include
#include
namespace KDevelop {
class AbstractDeclarationNavigationContextPrivate
{
public:
DeclarationPointer m_declaration;
bool m_fullBackwardSearch = false;
};
AbstractDeclarationNavigationContext::AbstractDeclarationNavigationContext(const DeclarationPointer& decl,
const TopDUContextPointer& topContext,
AbstractNavigationContext* previousContext)
: AbstractNavigationContext((topContext ? topContext : TopDUContextPointer(
decl ? decl->topContext() : nullptr)), previousContext)
, d(new AbstractDeclarationNavigationContextPrivate)
{
d->m_declaration = decl;
//Jump from definition to declaration if possible
auto* definition = dynamic_cast(d->m_declaration.data());
if (definition && definition->declaration())
d->m_declaration = DeclarationPointer(definition->declaration());
}
AbstractDeclarationNavigationContext::~AbstractDeclarationNavigationContext()
{
}
QString AbstractDeclarationNavigationContext::name() const
{
if (d->m_declaration.data())
return prettyQualifiedIdentifier(d->m_declaration).toString();
else
return declarationName(d->m_declaration);
}
QString AbstractDeclarationNavigationContext::html(bool shorten)
{
DUChainReadLocker lock(DUChain::lock(), 300);
if (!lock.locked()) {
return {};
}
clear();
AbstractNavigationContext::html(shorten);
- modifyHtml() += QLatin1String("") + fontSizePrefix(shorten);
+ modifyHtml() += QLatin1String("
");
addExternalHtml(prefix());
if (!d->m_declaration.data()) {
modifyHtml() += i18n("
lost declaration
");
return currentHtml();
}
if (auto context = previousContext()) {
const QString link = createLink(context->name(), context->name(),
NavigationAction(context));
modifyHtml() += navigationHighlight(i18n("Back to %1
", link));
}
QExplicitlySharedDataPointer doc;
if (!shorten) {
doc = ICore::self()->documentationController()->documentationForDeclaration(d->m_declaration.data());
const auto* function =
dynamic_cast(d->m_declaration.data());
if (function) {
htmlFunction();
} else if (d->m_declaration->isTypeAlias() || d->m_declaration->type() ||
d->m_declaration->kind() == Declaration::Instance) {
if (d->m_declaration->isTypeAlias())
modifyHtml() += importantHighlight(QStringLiteral("typedef "));
if (d->m_declaration->type())
modifyHtml() += i18n("enumerator ");
AbstractType::Ptr useType = d->m_declaration->abstractType();
if (d->m_declaration->isTypeAlias()) {
//Do not show the own name as type of typedefs
if (useType.cast())
useType = useType.cast()->type();
}
eventuallyMakeTypeLinks(useType);
modifyHtml() += QLatin1Char(' ') + identifierHighlight(declarationName(
d->m_declaration).toHtmlEscaped(),
d->m_declaration);
if (auto integralType = d->m_declaration->type()) {
const QString plainValue = integralType->valueAsString();
if (!plainValue.isEmpty()) {
modifyHtml() += QStringLiteral(" = ") + plainValue;
}
}
modifyHtml() += QStringLiteral("
");
} else {
if (d->m_declaration->kind() == Declaration::Type &&
d->m_declaration->abstractType().cast()) {
htmlClass();
}
if (d->m_declaration->kind() == Declaration::Namespace) {
modifyHtml() +=
i18n("namespace %1 ",
identifierHighlight(d->m_declaration->qualifiedIdentifier().toString().toHtmlEscaped(),
d->m_declaration));
} else if (d->m_declaration->kind() == Declaration::NamespaceAlias) {
modifyHtml() +=
identifierHighlight(declarationName(d->m_declaration).toHtmlEscaped(), d->m_declaration);
}
if (d->m_declaration->type()) {
EnumerationType::Ptr enumeration = d->m_declaration->type();
modifyHtml() +=
i18n("enumeration %1 ",
identifierHighlight(
d->m_declaration->identifier().toString().toHtmlEscaped(), d->m_declaration));
}
if (d->m_declaration->isForwardDeclaration()) {
auto* forwardDec = static_cast(d->m_declaration.data());
Declaration* resolved = forwardDec->resolve(topContext().data());
if (resolved) {
modifyHtml() += i18n("(resolved forward-declaration: ");
makeLink(resolved->identifier().toString(), DeclarationPointer(
resolved), NavigationAction::NavigateDeclaration);
modifyHtml() += i18n(") ");
} else {
modifyHtml() += i18n("(unresolved forward-declaration) ");
QualifiedIdentifier id = forwardDec->qualifiedIdentifier();
const auto& forwardDecFile = forwardDec->topContext()->parsingEnvironmentFile();
uint count;
const IndexedDeclaration* decls;
PersistentSymbolTable::self().declarations(id, count, decls);
for (uint a = 0; a < count; ++a) {
auto dec = decls[a].data();
if (!dec || dec->isForwardDeclaration()) {
continue;
}
const auto& decFile = forwardDec->topContext()->parsingEnvironmentFile();
if ((static_cast(decFile) != static_cast(forwardDecFile)) ||
(decFile && forwardDecFile && decFile->language() != forwardDecFile->language())) {
// the language of the declarations must match
continue;
}
modifyHtml() += QStringLiteral("
");
makeLink(i18n("possible resolution from"), DeclarationPointer(
dec), NavigationAction::NavigateDeclaration);
modifyHtml() += QLatin1Char(' ') + dec->url().str();
}
}
}
modifyHtml() += QStringLiteral("
");
}
} else {
AbstractType::Ptr showType = d->m_declaration->abstractType();
if (showType && showType.cast()) {
showType = showType.cast()->returnType();
if (showType)
modifyHtml() += labelHighlight(i18n("Returns: "));
} else if (showType) {
modifyHtml() += labelHighlight(i18n("Type: "));
}
if (showType) {
eventuallyMakeTypeLinks(showType);
modifyHtml() += QStringLiteral(" ");
}
}
QualifiedIdentifier identifier = d->m_declaration->qualifiedIdentifier();
if (identifier.count() > 1) {
if (d->m_declaration->context() && d->m_declaration->context()->owner()) {
Declaration* decl = d->m_declaration->context()->owner();
auto* definition = dynamic_cast(decl);
if (definition && definition->declaration())
decl = definition->declaration();
if (decl->abstractType().cast())
modifyHtml() += labelHighlight(i18n("Enum: "));
else
modifyHtml() += labelHighlight(i18n("Container: "));
makeLink(declarationName(DeclarationPointer(decl)), DeclarationPointer(
decl), NavigationAction::NavigateDeclaration);
modifyHtml() += QStringLiteral(" ");
} else {
QualifiedIdentifier parent = identifier;
parent.pop();
modifyHtml() += labelHighlight(i18n("Scope: %1 ", typeHighlight(parent.toString().toHtmlEscaped())));
}
}
if (shorten && !d->m_declaration->comment().isEmpty()) {
QString comment = QString::fromUtf8(d->m_declaration->comment());
if (comment.length() > 60) {
comment.truncate(60);
comment += QLatin1String("...");
}
comment.replace(QLatin1Char('\n'), QLatin1Char(' '));
comment.replace(QLatin1String("
"), QLatin1String(" "));
comment.replace(QLatin1String("
"), QLatin1String(" "));
modifyHtml() += commentHighlight(comment.toHtmlEscaped()) + QLatin1String(" ");
}
QString access = stringFromAccess(d->m_declaration);
if (!access.isEmpty())
modifyHtml() += labelHighlight(i18n("Access: %1 ", propertyHighlight(access.toHtmlEscaped())));
///@todo Enumerations
QString detailsHtml;
const QStringList details = declarationDetails(d->m_declaration);
if (!details.isEmpty()) {
bool first = true;
for (const QString& str : details) {
if (!first)
detailsHtml += QLatin1String(", ");
first = false;
detailsHtml += propertyHighlight(str);
}
}
QString kind = declarationKind(d->m_declaration);
if (!kind.isEmpty()) {
if (!detailsHtml.isEmpty())
modifyHtml() += labelHighlight(i18n("Kind: %1 %2 ", importantHighlight(kind.toHtmlEscaped()), detailsHtml));
else
modifyHtml() += labelHighlight(i18n("Kind: %1 ", importantHighlight(kind.toHtmlEscaped())));
}
if (d->m_declaration->isDeprecated()) {
modifyHtml() += labelHighlight(i18n("Status: %1 ", propertyHighlight(i18n("Deprecated"))));
}
modifyHtml() += QStringLiteral("
");
if (!shorten)
htmlAdditionalNavigation();
if (!shorten) {
if (dynamic_cast(d->m_declaration.data()))
modifyHtml() += labelHighlight(i18n("Def.: "));
else
modifyHtml() += labelHighlight(i18n("Decl.: "));
makeLink(QStringLiteral("%1 :%2").arg(d->m_declaration->url().toUrl().fileName()).arg(d->m_declaration->
rangeInCurrentRevision().
start().line() + 1), d->m_declaration,
NavigationAction::JumpToSource);
modifyHtml() += QStringLiteral(" ");
//modifyHtml() += "
";
if (!dynamic_cast(d->m_declaration.data())) {
if (FunctionDefinition* definition = FunctionDefinition::definition(d->m_declaration.data())) {
modifyHtml() += labelHighlight(i18n(" Def.: "));
makeLink(QStringLiteral("%1 :%2").arg(definition->url().toUrl().fileName()).arg(definition->
rangeInCurrentRevision()
.start().line() + 1), DeclarationPointer(
definition), NavigationAction::JumpToSource);
}
}
if (auto* definition = dynamic_cast(d->m_declaration.data())) {
if (definition->declaration()) {
modifyHtml() += labelHighlight(i18n(" Decl.: "));
makeLink(QStringLiteral("%1 :%2").arg(definition->declaration()->url().toUrl().fileName()).arg(
definition->declaration()->rangeInCurrentRevision().start().line() + 1),
DeclarationPointer(definition->declaration()), NavigationAction::JumpToSource);
}
}
modifyHtml() += QStringLiteral(" "); //The action name _must_ stay "show_uses", since that is also used from outside
makeLink(i18n("Show uses"), QStringLiteral("show_uses"),
NavigationAction(d->m_declaration, NavigationAction::NavigateUses));
}
QByteArray declarationComment = d->m_declaration->comment();
if (!shorten && (!declarationComment.isEmpty() || doc)) {
modifyHtml() += QStringLiteral("");
if (doc) {
QString comment = doc->description();
connect(
doc.data(), &IDocumentation::descriptionChanged, this,
&AbstractDeclarationNavigationContext::contentsChanged);
if (!comment.isEmpty()) {
modifyHtml() += QLatin1String("
") + commentHighlight(comment) + QLatin1String("
");
}
}
QString comment = QString::fromUtf8(declarationComment);
if (!comment.isEmpty()) {
// if the first paragraph does not contain a tag, we assume that this is a plain-text comment
if (!Qt::mightBeRichText(comment)) {
// still might contain extra html tags for line breaks (this is the case for doxygen-style comments sometimes)
// let's protect them from being removed completely
comment.replace(QRegExp(QStringLiteral("
")), QStringLiteral("\n"));
comment = comment.toHtmlEscaped();
comment.replace(QLatin1Char('\n'), QLatin1String("
")); //Replicate newlines in html
}
modifyHtml() += commentHighlight(comment);
modifyHtml() += QStringLiteral("
");
}
}
if (!shorten) {
modifyHtml() += declarationSizeInformation(d->m_declaration, topContext().data());
}
if (!shorten && doc) {
modifyHtml() += QLatin1String("") + i18n("Show documentation for ");
makeLink(prettyQualifiedName(d->m_declaration),
d->m_declaration, NavigationAction::ShowDocumentation);
modifyHtml() += QStringLiteral("
");
}
//modifyHtml() += "
";
addExternalHtml(suffix());
- modifyHtml() += fontSizeSuffix(shorten) + QLatin1String("
");
+ modifyHtml() += QLatin1String("");
return currentHtml();
}
AbstractType::Ptr AbstractDeclarationNavigationContext::typeToShow(AbstractType::Ptr type)
{
return type;
}
void AbstractDeclarationNavigationContext::htmlFunction()
{
const auto* function =
dynamic_cast(d->m_declaration.data());
Q_ASSERT(function);
const auto* classFunDecl =
dynamic_cast(d->m_declaration.data());
const FunctionType::Ptr type = d->m_declaration->abstractType().cast();
if (!type) {
modifyHtml() += errorHighlight(QStringLiteral("Invalid type
"));
return;
}
if (!classFunDecl || (!classFunDecl->isConstructor() && !classFunDecl->isDestructor())) {
// only print return type for global functions and non-ctor/dtor methods
eventuallyMakeTypeLinks(type->returnType());
}
modifyHtml() += QLatin1Char(' ') + identifierHighlight(prettyIdentifier(
d->m_declaration).toString().toHtmlEscaped(),
d->m_declaration);
if (type->indexedArgumentsSize() == 0) {
modifyHtml() += QStringLiteral("()");
} else {
modifyHtml() += QStringLiteral("( ");
bool first = true;
int firstDefaultParam = type->indexedArgumentsSize() - function->defaultParametersSize();
int currentArgNum = 0;
QVector decls;
if (DUContext* argumentContext = DUChainUtils::argumentContext(d->m_declaration.data())) {
decls = argumentContext->localDeclarations(topContext().data());
}
foreach (const AbstractType::Ptr& argType, type->arguments()) {
if (!first)
modifyHtml() += QStringLiteral(", ");
first = false;
eventuallyMakeTypeLinks(argType);
// Must count from the back to skip possible template arguments before the function arguments.
int currentArgIndex = decls.size() - type->arguments().size() + currentArgNum;
if (currentArgIndex >= 0 && currentArgIndex < decls.size()) {
modifyHtml() += QLatin1Char(' ') + identifierHighlight(
decls[currentArgIndex]->identifier().toString().toHtmlEscaped(), d->m_declaration);
}
if (currentArgNum >= firstDefaultParam) {
IndexedString defaultStr = function->defaultParameters()[currentArgNum - firstDefaultParam];
if (!defaultStr.isEmpty()) {
modifyHtml() += QLatin1String(" = ") + defaultStr.str().toHtmlEscaped();
}
}
++currentArgNum;
}
modifyHtml() += QStringLiteral(" )");
}
modifyHtml() += QStringLiteral("
");
}
Identifier AbstractDeclarationNavigationContext::prettyIdentifier(const DeclarationPointer& decl) const
{
Identifier ret;
QualifiedIdentifier q = prettyQualifiedIdentifier(decl);
if (!q.isEmpty())
ret = q.last();
return ret;
}
QualifiedIdentifier AbstractDeclarationNavigationContext::prettyQualifiedIdentifier(const DeclarationPointer& decl)
const
{
if (decl)
return decl->qualifiedIdentifier();
else
return QualifiedIdentifier();
}
QString AbstractDeclarationNavigationContext::prettyQualifiedName(const DeclarationPointer& decl) const
{
const auto qid = prettyQualifiedIdentifier(decl);
if (qid.isEmpty()) {
return i18nc("An anonymous declaration (class, function, etc.)", "");
}
return qid.toString();
}
void AbstractDeclarationNavigationContext::htmlAdditionalNavigation()
{
///Check if the function overrides or hides another one
const auto* classFunDecl =
dynamic_cast(d->m_declaration.data());
if (classFunDecl) {
Declaration* overridden = DUChainUtils::overridden(d->m_declaration.data());
if (overridden) {
modifyHtml() += i18n("Overrides a ");
makeLink(i18n("function"), QStringLiteral("jump_to_overridden"),
NavigationAction(DeclarationPointer(overridden), NavigationAction::NavigateDeclaration));
modifyHtml() += i18n(" from ");
makeLink(prettyQualifiedName(DeclarationPointer(overridden->context()->owner())),
QStringLiteral("jump_to_overridden_container"),
NavigationAction(DeclarationPointer(overridden->context()->owner()),
NavigationAction::NavigateDeclaration));
modifyHtml() += QStringLiteral("
");
} else {
//Check if this declarations hides other declarations
QList decls;
foreach (const DUContext::Import& import, d->m_declaration->context()->importedParentContexts())
if (import.context(topContext().data()))
decls +=
import.context(topContext().data())->findDeclarations(QualifiedIdentifier(d->m_declaration->
identifier()),
CursorInRevision::invalid(),
AbstractType::Ptr(),
topContext().data(),
DUContext::DontSearchInParent);
uint num = 0;
foreach (Declaration* decl, decls) {
modifyHtml() += i18n("Hides a ");
makeLink(i18n("function"), QStringLiteral("jump_to_hide_%1").arg(num),
NavigationAction(DeclarationPointer(decl),
NavigationAction::NavigateDeclaration));
modifyHtml() += i18n(" from ");
makeLink(prettyQualifiedName(DeclarationPointer(decl->context()->owner())),
QStringLiteral("jump_to_hide_container_%1").arg(num),
NavigationAction(DeclarationPointer(decl->context()->owner()),
NavigationAction::NavigateDeclaration));
modifyHtml() += QStringLiteral("
");
++num;
}
}
///Show all places where this function is overridden
if (classFunDecl->isVirtual()) {
Declaration* classDecl = d->m_declaration->context()->owner();
if (classDecl) {
uint maxAllowedSteps = d->m_fullBackwardSearch ? (uint) - 1 : 10;
const QList overriders =
DUChainUtils::overriders(classDecl, classFunDecl, maxAllowedSteps);
if (!overriders.isEmpty()) {
modifyHtml() += i18n("Overridden in ");
bool first = true;
for (Declaration* overrider : overriders) {
if (!first)
modifyHtml() += QStringLiteral(", ");
first = false;
const auto owner = DeclarationPointer(overrider->context()->owner());
const QString name = prettyQualifiedName(owner);
makeLink(name, name,
NavigationAction(DeclarationPointer(overrider),
NavigationAction::NavigateDeclaration));
}
modifyHtml() += QStringLiteral("
");
}
if (maxAllowedSteps == 0)
createFullBackwardSearchLink(overriders.isEmpty() ? i18n("Overriders possible, show all") : i18n(
"More overriders possible, show all"));
}
}
}
///Show all classes that inherit this one
uint maxAllowedSteps = d->m_fullBackwardSearch ? (uint) - 1 : 10;
const QList inheriters = DUChainUtils::inheriters(d->m_declaration.data(), maxAllowedSteps);
if (!inheriters.isEmpty()) {
modifyHtml() += i18n("Inherited by ");
bool first = true;
for (Declaration* importer : inheriters) {
if (!first)
modifyHtml() += QStringLiteral(", ");
first = false;
const QString importerName = prettyQualifiedName(DeclarationPointer(importer));
makeLink(importerName, importerName,
NavigationAction(DeclarationPointer(importer), NavigationAction::NavigateDeclaration));
}
modifyHtml() += QStringLiteral("
");
}
if (maxAllowedSteps == 0)
createFullBackwardSearchLink(inheriters.isEmpty() ? i18n("Inheriters possible, show all") : i18n(
"More inheriters possible, show all"));
}
void AbstractDeclarationNavigationContext::createFullBackwardSearchLink(const QString& string)
{
makeLink(string, QStringLiteral("m_fullBackwardSearch=true"),
NavigationAction(QStringLiteral("m_fullBackwardSearch=true")));
modifyHtml() += QStringLiteral("
");
}
NavigationContextPointer AbstractDeclarationNavigationContext::executeKeyAction(const QString& key)
{
if (key == QLatin1String("m_fullBackwardSearch=true")) {
d->m_fullBackwardSearch = true;
clear();
}
return NavigationContextPointer(this);
}
void AbstractDeclarationNavigationContext::htmlClass()
{
StructureType::Ptr klass = d->m_declaration->abstractType().cast();
Q_ASSERT(klass);
ClassDeclaration* classDecl = dynamic_cast(klass->declaration(topContext().data()));
if (classDecl) {
switch (classDecl->classType()) {
case ClassDeclarationData::Class:
modifyHtml() += QStringLiteral("class ");
break;
case ClassDeclarationData::Struct:
modifyHtml() += QStringLiteral("struct ");
break;
case ClassDeclarationData::Union:
modifyHtml() += QStringLiteral("union ");
break;
case ClassDeclarationData::Interface:
modifyHtml() += QStringLiteral("interface ");
break;
case ClassDeclarationData::Trait:
modifyHtml() += QStringLiteral("trait ");
break;
}
eventuallyMakeTypeLinks(klass.cast());
FOREACH_FUNCTION(const BaseClassInstance &base, classDecl->baseClasses) {
modifyHtml() += QLatin1String(", ") + stringFromAccess(base.access) + QLatin1Char(' ') +
(base.virtualInheritance ? QStringLiteral("virtual") : QString()) + QLatin1Char(' ');
eventuallyMakeTypeLinks(base.baseClass.abstractType());
}
} else {
/// @todo How can we get here? and should this really be a class?
modifyHtml() += QStringLiteral("class ");
eventuallyMakeTypeLinks(klass.cast());
}
modifyHtml() += QStringLiteral(" ");
}
void AbstractDeclarationNavigationContext::htmlIdentifiedType(AbstractType::Ptr type, const IdentifiedType* idType)
{
if (!type) {
qCDebug(LANGUAGE) << "null type!";
return;
}
if (!idType) {
qCDebug(LANGUAGE) << "no identified type for" << type->toString();
modifyHtml() += typeHighlight(type->toString().toHtmlEscaped());
return;
}
auto* decl = idType->declaration(topContext().data());
if (!decl) {
qCDebug(LANGUAGE) << "could not resolve declaration:" << idType->declarationId().isDirect() <<
idType->qualifiedIdentifier().toString() << "in top-context" << topContext()->url().str();
modifyHtml() += typeHighlight(type->toString().toHtmlEscaped());
return;
}
//Remove the last template-identifiers, because we create those directly
QualifiedIdentifier id = prettyQualifiedIdentifier(DeclarationPointer(decl));
Identifier lastId = id.last();
id.pop();
lastId.clearTemplateIdentifiers();
id.push(lastId);
if (decl->context() && decl->context()->owner()) {
//Also create full type-links for the context around
AbstractType::Ptr contextType = decl->context()->owner()->abstractType();
auto* contextIdType = dynamic_cast(contextType.data());
if (contextIdType && !contextIdType->equals(idType)) {
//Create full type information for the context
if (!id.isEmpty())
id = id.mid(id.count() - 1);
htmlIdentifiedType(contextType, contextIdType);
modifyHtml() += QStringLiteral("::").toHtmlEscaped();
}
}
//We leave out the * and & reference and pointer signs, those are added to the end
makeLink(id.toString(), DeclarationPointer(idType->declaration(
topContext().data())), NavigationAction::NavigateDeclaration);
}
void AbstractDeclarationNavigationContext::eventuallyMakeTypeLinks(AbstractType::Ptr type)
{
type = typeToShow(type);
if (!type) {
modifyHtml() += typeHighlight(QStringLiteral("").toHtmlEscaped());
return;
}
AbstractType::Ptr target = TypeUtils::targetTypeKeepAliases(type, topContext().data());
const auto* idType = dynamic_cast(target.data());
qCDebug(LANGUAGE) << "making type-links for" << type->toString();
if (idType && idType->declaration(topContext().data())) {
///@todo This is C++ specific, move into subclass
if (target->modifiers() & AbstractType::ConstModifier)
modifyHtml() += typeHighlight(QStringLiteral("const "));
htmlIdentifiedType(target, idType);
//We need to exchange the target type, else template-parameters may confuse this
SimpleTypeExchanger exchangeTarget(target, AbstractType::Ptr());
AbstractType::Ptr exchanged = exchangeTarget.exchange(type);
if (exchanged) {
QString typeSuffixString = exchanged->toString();
QRegExp suffixExp(QStringLiteral("\\&|\\*"));
int suffixPos = typeSuffixString.indexOf(suffixExp);
if (suffixPos != -1)
modifyHtml() += typeHighlight(typeSuffixString.mid(suffixPos));
}
} else {
if (idType) {
qCDebug(LANGUAGE) << "identified type could not be resolved:" << idType->qualifiedIdentifier() <<
idType->declarationId().isValid() << idType->declarationId().isDirect();
}
modifyHtml() += typeHighlight(type->toString().toHtmlEscaped());
}
}
DeclarationPointer AbstractDeclarationNavigationContext::declaration() const
{
return d->m_declaration;
}
QString AbstractDeclarationNavigationContext::identifierHighlight(const QString& identifier,
const DeclarationPointer& decl) const
{
QString ret = nameHighlight(identifier);
if (!decl) {
return ret;
}
if (decl->isDeprecated()) {
ret = QStringLiteral("") + ret + QStringLiteral("");
}
return ret;
}
QString AbstractDeclarationNavigationContext::stringFromAccess(Declaration::AccessPolicy access)
{
switch (access) {
case Declaration::Private:
return QStringLiteral("private");
case Declaration::Protected:
return QStringLiteral("protected");
case Declaration::Public:
return QStringLiteral("public");
default:
break;
}
return QString();
}
QString AbstractDeclarationNavigationContext::stringFromAccess(const DeclarationPointer& decl)
{
const auto* memberDecl = dynamic_cast(decl.data());
if (memberDecl) {
return stringFromAccess(memberDecl->accessPolicy());
}
return QString();
}
QString AbstractDeclarationNavigationContext::declarationName(const DeclarationPointer& decl) const
{
if (auto* alias = dynamic_cast(decl.data())) {
if (alias->identifier().isEmpty())
return QLatin1String("using namespace ") + alias->importIdentifier().toString();
else
return QLatin1String("namespace ") + alias->identifier().toString() + QLatin1String(" = ") +
alias->importIdentifier().toString();
}
if (!decl)
return i18nc("A declaration that is unknown", "Unknown");
else
return prettyIdentifier(decl).toString();
}
QStringList AbstractDeclarationNavigationContext::declarationDetails(const DeclarationPointer& decl)
{
QStringList details;
const auto* function = dynamic_cast(decl.data());
const auto* memberDecl = dynamic_cast(decl.data());
if (memberDecl) {
if (memberDecl->isMutable())
details << QStringLiteral("mutable");
if (memberDecl->isRegister())
details << QStringLiteral("register");
if (memberDecl->isStatic())
details << QStringLiteral("static");
if (memberDecl->isAuto())
details << QStringLiteral("auto");
if (memberDecl->isExtern())
details << QStringLiteral("extern");
if (memberDecl->isFriend())
details << QStringLiteral("friend");
}
if (decl->isDefinition())
details << i18nc("tells if a declaration is defining the variable's value", "definition");
if (decl->isExplicitlyDeleted())
details << QStringLiteral("deleted");
if (memberDecl && memberDecl->isForwardDeclaration())
details << i18nc("as in c++ forward declaration", "forward");
AbstractType::Ptr t(decl->abstractType());
if (t) {
if (t->modifiers() & AbstractType::ConstModifier)
details << i18nc("a variable that won't change, const", "constant");
if (t->modifiers() & AbstractType::VolatileModifier)
details << QStringLiteral("volatile");
}
if (function) {
if (function->isInline())
details << QStringLiteral("inline");
if (function->isExplicit())
details << QStringLiteral("explicit");
if (function->isVirtual())
details << QStringLiteral("virtual");
const auto* classFunDecl = dynamic_cast(decl.data());
if (classFunDecl) {
if (classFunDecl->isSignal())
details << QStringLiteral("signal");
if (classFunDecl->isSlot())
details << QStringLiteral("slot");
if (classFunDecl->isFinal())
details << QStringLiteral("final");
if (classFunDecl->isConstructor())
details << QStringLiteral("constructor");
if (classFunDecl->isDestructor())
details << QStringLiteral("destructor");
if (classFunDecl->isConversionFunction())
details << QStringLiteral("conversion-function");
if (classFunDecl->isAbstract())
details << QStringLiteral("abstract");
}
}
return details;
}
QString AbstractDeclarationNavigationContext::declarationSizeInformation(const DeclarationPointer& decl,
const TopDUContext* topContext)
{
if (!decl) {
return {};
}
if (decl->isTypeAlias()) {
// show size information for underlying type of aliases / typedefs etc.
const auto type = TypeUtils::targetType(decl->abstractType(), topContext);
if (const auto* idType = dynamic_cast(type.data())) {
return declarationSizeInformation(DeclarationPointer(idType->declaration(topContext)), topContext);
}
return {};
}
// Note that ClassMemberDeclaration also includes ClassDeclaration, which uses the sizeOf and alignOf fields,
// but normally leaves the bitOffsetOf unset (-1).
const auto* memberDecl = dynamic_cast(decl.data());
if (memberDecl && (memberDecl->bitOffsetOf() > 0 || memberDecl->sizeOf() > 0 || memberDecl->alignOf() > 0)) {
QString sizeInfo = QStringLiteral("");
if (memberDecl->bitOffsetOf() >= 0) {
const auto byteOffset = memberDecl->bitOffsetOf() / 8;
const auto bitOffset = memberDecl->bitOffsetOf() % 8;
const QString byteOffsetStr = i18np("1 Byte", "%1 Bytes", byteOffset);
const QString bitOffsetStr = bitOffset ? i18np("1 Bit", "%1 Bits", bitOffset) : QString();
sizeInfo +=
i18n("offset in parent: %1", bitOffset ? i18nc("%1: bytes, %2: bits", "%1, %2", byteOffsetStr,
bitOffsetStr) : byteOffsetStr) + QLatin1String("; ");
}
if (memberDecl->sizeOf() >= 0) {
sizeInfo += i18n("size: %1 Bytes", memberDecl->sizeOf()) + QLatin1String("; ");
}
if (memberDecl->alignOf() >= 0) {
sizeInfo += i18n("aligned to: %1 Bytes", memberDecl->alignOf());
}
sizeInfo += QStringLiteral("
");
return sizeInfo;
}
return QString();
}
}
diff --git a/kdevplatform/language/duchain/navigation/abstractincludenavigationcontext.cpp b/kdevplatform/language/duchain/navigation/abstractincludenavigationcontext.cpp
index 1bdaba5edf..f5a706ff90 100644
--- a/kdevplatform/language/duchain/navigation/abstractincludenavigationcontext.cpp
+++ b/kdevplatform/language/duchain/navigation/abstractincludenavigationcontext.cpp
@@ -1,183 +1,183 @@
/*
Copyright 2007 David Nolden
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "abstractincludenavigationcontext.h"
#include
#include
#include
#include
namespace KDevelop {
AbstractIncludeNavigationContext::AbstractIncludeNavigationContext(const IncludeItem& item,
const TopDUContextPointer& topContext,
const ParsingEnvironmentType& type)
: AbstractNavigationContext(topContext)
, m_type(type)
, m_item(item)
{}
TopDUContext* pickContextWithData(const QList& duchains, uint maxDepth,
const ParsingEnvironmentType& type,
bool forcePick = true)
{
TopDUContext* duchain = nullptr;
for (TopDUContext* ctx : duchains) {
if (!ctx->parsingEnvironmentFile() || ctx->parsingEnvironmentFile()->type() != type)
continue;
if (ctx->childContexts().count() != 0
&& (duchain == nullptr || ctx->childContexts().count() > duchain->childContexts().count())) {
duchain = ctx;
}
if (ctx->localDeclarations().count() != 0
&& (duchain == nullptr || ctx->localDeclarations().count() > duchain->localDeclarations().count())) {
duchain = ctx;
}
}
if (!duchain && maxDepth != 0) {
if (maxDepth != 0) {
for (TopDUContext* ctx : duchains) {
QList children;
foreach (const DUContext::Import& import, ctx->importedParentContexts())
if (import.context(nullptr))
children << import.context(nullptr)->topContext();
duchain = pickContextWithData(children, maxDepth - 1, type, false);
if (duchain)
break;
}
}
}
if (!duchain && !duchains.isEmpty() && forcePick)
duchain = duchains.first();
return duchain;
}
QString AbstractIncludeNavigationContext::html(bool shorten)
{
clear();
- modifyHtml() += QLatin1String("") + fontSizePrefix(shorten);
+ modifyHtml() += QLatin1String("
");
addExternalHtml(prefix());
QUrl u = m_item.url();
NavigationAction action(u, KTextEditor::Cursor(0, 0));
makeLink(u.toDisplayString(QUrl::PreferLocalFile), u.toString(), action);
modifyHtml() += QStringLiteral("
");
QList duchains = DUChain::self()->chainsForDocument(u);
//Pick the one duchain for this document that has the most child-contexts/declarations.
//This prevents picking a context that is empty due to header-guards.
TopDUContext* duchain = pickContextWithData(duchains, 2, m_type);
if (duchain) {
getFileInfo(duchain);
if (!shorten) {
modifyHtml() += labelHighlight(i18n("Declarations:")) + QLatin1String("
");
bool first = true;
QVector decs;
addDeclarationsFromContext(duchain, first, decs);
}
} else if (duchains.isEmpty()) {
modifyHtml() += i18n("not parsed yet");
}
addExternalHtml(suffix());
- modifyHtml() += fontSizeSuffix(shorten) + QLatin1String("
");
+ modifyHtml() += QLatin1String("");
return currentHtml();
}
void AbstractIncludeNavigationContext::getFileInfo(TopDUContext* duchain)
{
modifyHtml() +=
QStringLiteral("%1: %2 %3: %4").arg(labelHighlight(i18nc("Files included into this file", "Includes"))).arg(
duchain->importedParentContexts().count()).arg(labelHighlight(i18nc(
"Count of files this file was included into",
"Included by"))).arg(
duchain->importers().count());
modifyHtml() += QStringLiteral("
");
}
QString AbstractIncludeNavigationContext::name() const
{
return m_item.name;
}
bool AbstractIncludeNavigationContext::filterDeclaration(Declaration* /*decl*/)
{
return true;
}
void AbstractIncludeNavigationContext::addDeclarationsFromContext(KDevelop::DUContext* ctx, bool& first,
QVector& addedDeclarations,
const QString& indent)
{
//modifyHtml() += indent + ctx->localScopeIdentifier().toString() + "{
";
QVector children = ctx->childContexts();
QVector declarations = ctx->localDeclarations();
QVector::const_iterator childIterator = children.constBegin();
QVector::const_iterator declarationIterator = declarations.constBegin();
while (childIterator != children.constEnd() || declarationIterator != declarations.constEnd()) {
//Show declarations/contexts in the order they appear in the file
int currentDeclarationLine = -1;
int currentContextLine = -1;
if (declarationIterator != declarations.constEnd())
currentDeclarationLine = (*declarationIterator)->rangeInCurrentRevision().start().line();
if (childIterator != children.constEnd())
currentDeclarationLine = (*childIterator)->rangeInCurrentRevision().start().line();
if ((currentDeclarationLine <= currentContextLine || currentContextLine == -1 ||
childIterator == children.constEnd()) && declarationIterator != declarations.constEnd()) {
IdentifierPair id = qMakePair(static_cast((*declarationIterator)->kind()),
(*declarationIterator)->qualifiedIdentifier().index());
if (!addedDeclarations.contains(id) && filterDeclaration(*declarationIterator)) {
//Show the declaration
if (!first)
modifyHtml() += QStringLiteral(", ");
else
first = false;
modifyHtml() += QString(indent + declarationKind(DeclarationPointer(
*declarationIterator)) +
QLatin1Char(' ')).toHtmlEscaped();
makeLink((*declarationIterator)->qualifiedIdentifier().toString(),
DeclarationPointer(*declarationIterator), NavigationAction::NavigateDeclaration);
addedDeclarations << id;
}
++declarationIterator;
} else {
//Eventually Recurse into the context
if ((*childIterator)->type() == DUContext::Global ||
(*childIterator)->type() == DUContext::Namespace /*|| (*childIterator)->type() == DUContext::Class*/)
addDeclarationsFromContext(*childIterator, first, addedDeclarations, indent + QLatin1Char(' '));
++childIterator;
}
}
//modifyHtml() += "}
";
}
}
diff --git a/kdevplatform/language/duchain/navigation/abstractnavigationcontext.cpp b/kdevplatform/language/duchain/navigation/abstractnavigationcontext.cpp
index 92d52b8868..a4c29e68bc 100644
--- a/kdevplatform/language/duchain/navigation/abstractnavigationcontext.cpp
+++ b/kdevplatform/language/duchain/navigation/abstractnavigationcontext.cpp
@@ -1,582 +1,572 @@
/*
Copyright 2007 David Nolden
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "abstractnavigationcontext.h"
#include
#include
#include "abstractdeclarationnavigationcontext.h"
#include "abstractnavigationwidget.h"
#include "usesnavigationcontext.h"
#include "../../../interfaces/icore.h"
#include "../../../interfaces/idocumentcontroller.h"
#include "../functiondeclaration.h"
#include "../namespacealiasdeclaration.h"
#include "../types/functiontype.h"
#include "../types/structuretype.h"
#include
#include
#include
#include
namespace KDevelop {
class AbstractNavigationContextPrivate
{
public:
QVector m_children; //Used to keep alive all children until this is deleted
int m_selectedLink = 0; //The link currently selected
NavigationAction m_selectedLinkAction; //Target of the currently selected link
bool m_shorten = false;
//A counter used while building the html-code to count the used links.
int m_linkCount = -1;
//Something else than -1 if the current position is represented by a line-number, not a link.
int m_currentLine = 0;
int m_currentPositionLine = 0;
QMap m_links;
QMap m_linkLines; //Holds the line for each link
QMap m_intLinks;
AbstractNavigationContext* m_previousContext;
QString m_prefix, m_suffix;
TopDUContextPointer m_topContext;
QString m_currentText; //Here the text is built
};
void AbstractNavigationContext::setTopContext(const TopDUContextPointer& context)
{
d->m_topContext = context;
}
TopDUContextPointer AbstractNavigationContext::topContext() const
{
return d->m_topContext;
}
AbstractNavigationContext::AbstractNavigationContext(const TopDUContextPointer& topContext,
AbstractNavigationContext* previousContext)
: d(new AbstractNavigationContextPrivate)
{
d->m_previousContext = previousContext;
d->m_topContext = topContext;
qRegisterMetaType("KTextEditor::Cursor");
qRegisterMetaType("IDocumentation::Ptr");
}
AbstractNavigationContext::~AbstractNavigationContext()
{
}
void AbstractNavigationContext::addExternalHtml(const QString& text)
{
int lastPos = 0;
int pos = 0;
QString fileMark = QStringLiteral("KDEV_FILE_LINK{");
while (pos < text.length() && (pos = text.indexOf(fileMark, pos)) != -1) {
modifyHtml() += text.mid(lastPos, pos - lastPos);
pos += fileMark.length();
if (pos != text.length()) {
int fileEnd = text.indexOf(QLatin1Char('}'), pos);
if (fileEnd != -1) {
QString file = text.mid(pos, fileEnd - pos);
pos = fileEnd + 1;
const QUrl url = QUrl::fromUserInput(file);
makeLink(url.fileName(), file, NavigationAction(url, KTextEditor::Cursor()));
}
}
lastPos = pos;
}
modifyHtml() += text.mid(lastPos, text.length() - lastPos);
}
void AbstractNavigationContext::makeLink(const QString& name, const DeclarationPointer& declaration,
NavigationAction::Type actionType)
{
NavigationAction action(declaration, actionType);
makeLink(name, QString(), action);
}
QString AbstractNavigationContext::createLink(const QString& name, const QString&, const NavigationAction& action)
{
if (d->m_shorten) {
//Do not create links in shortened mode, it's only for viewing
return typeHighlight(name.toHtmlEscaped());
}
// NOTE: Since the by definition in the HTML standard some uri components
// are case-insensitive, we define a new lowercase link-id for each
// link. Otherwise Qt 5 seems to mess up the casing and the link
// cannot be matched when it's executed.
QString hrefId = QStringLiteral("link_%1").arg(d->m_links.count());
d->m_links[hrefId] = action;
d->m_intLinks[d->m_linkCount] = action;
d->m_linkLines[d->m_linkCount] = d->m_currentLine;
if (d->m_currentPositionLine == d->m_currentLine) {
d->m_currentPositionLine = -1;
d->m_selectedLink = d->m_linkCount;
}
QString str = name.toHtmlEscaped();
if (d->m_linkCount == d->m_selectedLink)
str = QLatin1String("") + str + QLatin1String(
"");
QString ret = QLatin1String("m_linkCount == d->m_selectedLink &&
d->m_currentPositionLine ==
-1) ? QStringLiteral(" name = \"currentPosition\"") : QString()) + QLatin1Char('>') + str +
QLatin1String("");
if (d->m_selectedLink == d->m_linkCount)
d->m_selectedLinkAction = action;
++d->m_linkCount;
return ret;
}
void AbstractNavigationContext::makeLink(const QString& name, const QString& targetId, const NavigationAction& action)
{
modifyHtml() += createLink(name, targetId, action);
}
void AbstractNavigationContext::clear()
{
d->m_linkCount = 0;
d->m_currentLine = 0;
d->m_currentText.clear();
d->m_links.clear();
d->m_intLinks.clear();
d->m_linkLines.clear();
}
void AbstractNavigationContext::executeLink(const QString& link)
{
const auto actionIt = d->m_links.constFind(link);
if (actionIt == d->m_links.constEnd())
return;
execute(*actionIt);
}
NavigationContextPointer AbstractNavigationContext::executeKeyAction(const QString& key)
{
Q_UNUSED(key);
return NavigationContextPointer(this);
}
NavigationContextPointer AbstractNavigationContext::execute(const NavigationAction& action)
{
if (action.targetContext)
return NavigationContextPointer(action.targetContext);
if (action.type == NavigationAction::ExecuteKey)
return executeKeyAction(action.key);
if (!action.decl && (action.type != NavigationAction::JumpToSource || action.document.isEmpty())) {
qCDebug(LANGUAGE) << "Navigation-action has invalid declaration" << endl;
return NavigationContextPointer(this);
}
switch (action.type) {
case NavigationAction::ExecuteKey:
break;
case NavigationAction::None:
qCDebug(LANGUAGE) << "Tried to execute an invalid action in navigation-widget" << endl;
break;
case NavigationAction::NavigateDeclaration:
{
auto ctx = dynamic_cast(d->m_previousContext);
if (ctx && ctx->declaration() == action.decl)
return NavigationContextPointer(d->m_previousContext);
return registerChild(action.decl);
}
case NavigationAction::NavigateUses:
{
auto* browser = ICore::self()->pluginController()->extensionForPlugin();
if (browser) {
browser->showUses(action.decl);
return NavigationContextPointer(this);
}
Q_FALLTHROUGH();
}
case NavigationAction::ShowUses: {
return registerChild(new UsesNavigationContext(action.decl.data(), this));
}
case NavigationAction::JumpToSource:
{
QUrl doc = action.document;
KTextEditor::Cursor cursor = action.cursor;
{
DUChainReadLocker lock(DUChain::lock());
if (action.decl) {
if (doc.isEmpty()) {
doc = action.decl->url().toUrl();
/* if(action.decl->internalContext())
cursor = action.decl->internalContext()->range().start() + KTextEditor::Cursor(0, 1);
else*/
cursor = action.decl->rangeInCurrentRevision().start();
}
action.decl->activateSpecialization();
}
}
//This is used to execute the slot delayed in the event-loop, so crashes are avoided
QMetaObject::invokeMethod(ICore::self()->documentController(), "openDocument", Qt::QueuedConnection,
Q_ARG(QUrl, doc), Q_ARG(KTextEditor::Cursor, cursor));
break;
}
case NavigationAction::ShowDocumentation: {
auto doc = ICore::self()->documentationController()->documentationForDeclaration(action.decl.data());
// This is used to execute the slot delayed in the event-loop, so crashes are avoided
// which can happen e.g. due to focus change events resulting in tooltip destruction and thus this object
QMetaObject::invokeMethod(
ICore::self()->documentationController(), "showDocumentation", Qt::QueuedConnection,
Q_ARG(IDocumentation::Ptr, doc));
}
break;
}
return NavigationContextPointer(this);
}
AbstractNavigationContext* AbstractNavigationContext::previousContext() const
{
return d->m_previousContext;
}
void AbstractNavigationContext::setPreviousContext(AbstractNavigationContext* previous)
{
d->m_previousContext = previous;
}
NavigationContextPointer AbstractNavigationContext::registerChild(AbstractNavigationContext* context)
{
d->m_children << NavigationContextPointer(context);
return d->m_children.last();
}
NavigationContextPointer AbstractNavigationContext::registerChild(const DeclarationPointer& declaration)
{
//We create a navigation-widget here, and steal its context.. evil ;)
QScopedPointer navigationWidget(declaration->context()->createNavigationWidget(declaration.data()));
if (auto* abstractNavigationWidget =
dynamic_cast(navigationWidget.data())) {
NavigationContextPointer ret = abstractNavigationWidget->context();
ret->setPreviousContext(this);
d->m_children << ret;
return ret;
} else {
return NavigationContextPointer(this);
}
}
const int lineJump = 3;
void AbstractNavigationContext::down()
{
//Make sure link-count is valid
if (d->m_linkCount == -1) {
DUChainReadLocker lock;
html();
}
int fromLine = d->m_currentPositionLine;
if (d->m_selectedLink >= 0 && d->m_selectedLink < d->m_linkCount) {
if (fromLine == -1)
fromLine = d->m_linkLines[d->m_selectedLink];
for (int newSelectedLink = d->m_selectedLink + 1; newSelectedLink < d->m_linkCount; ++newSelectedLink) {
if (d->m_linkLines[newSelectedLink] > fromLine && d->m_linkLines[newSelectedLink] - fromLine <= lineJump) {
d->m_selectedLink = newSelectedLink;
d->m_currentPositionLine = -1;
return;
}
}
}
if (fromLine == -1)
fromLine = 0;
d->m_currentPositionLine = fromLine + lineJump;
if (d->m_currentPositionLine > d->m_currentLine)
d->m_currentPositionLine = d->m_currentLine;
}
void AbstractNavigationContext::up()
{
//Make sure link-count is valid
if (d->m_linkCount == -1) {
DUChainReadLocker lock;
html();
}
int fromLine = d->m_currentPositionLine;
if (d->m_selectedLink >= 0 && d->m_selectedLink < d->m_linkCount) {
if (fromLine == -1)
fromLine = d->m_linkLines[d->m_selectedLink];
for (int newSelectedLink = d->m_selectedLink - 1; newSelectedLink >= 0; --newSelectedLink) {
if (d->m_linkLines[newSelectedLink] < fromLine && fromLine - d->m_linkLines[newSelectedLink] <= lineJump) {
d->m_selectedLink = newSelectedLink;
d->m_currentPositionLine = -1;
return;
}
}
}
if (fromLine == -1)
fromLine = d->m_currentLine;
d->m_currentPositionLine = fromLine - lineJump;
if (d->m_currentPositionLine < 0)
d->m_currentPositionLine = 0;
}
void AbstractNavigationContext::nextLink()
{
//Make sure link-count is valid
if (d->m_linkCount == -1) {
DUChainReadLocker lock;
html();
}
d->m_currentPositionLine = -1;
if (d->m_linkCount > 0)
d->m_selectedLink = (d->m_selectedLink + 1) % d->m_linkCount;
}
void AbstractNavigationContext::previousLink()
{
//Make sure link-count is valid
if (d->m_linkCount == -1) {
DUChainReadLocker lock;
html();
}
d->m_currentPositionLine = -1;
if (d->m_linkCount > 0) {
--d->m_selectedLink;
if (d->m_selectedLink < 0)
d->m_selectedLink += d->m_linkCount;
}
Q_ASSERT(d->m_selectedLink >= 0);
}
int AbstractNavigationContext::linkCount() const
{
return d->m_linkCount;
}
QString AbstractNavigationContext::prefix() const
{
return d->m_prefix;
}
QString AbstractNavigationContext::suffix() const
{
return d->m_suffix;
}
void AbstractNavigationContext::setPrefixSuffix(const QString& prefix, const QString& suffix)
{
d->m_prefix = prefix;
d->m_suffix = suffix;
}
NavigationContextPointer AbstractNavigationContext::back()
{
if (d->m_previousContext)
return NavigationContextPointer(d->m_previousContext);
else
return NavigationContextPointer(this);
}
NavigationContextPointer AbstractNavigationContext::accept()
{
if (d->m_selectedLink >= 0 && d->m_selectedLink < d->m_linkCount) {
NavigationAction action = d->m_intLinks[d->m_selectedLink];
return execute(action);
}
return NavigationContextPointer(this);
}
NavigationContextPointer AbstractNavigationContext::accept(IndexedDeclaration decl)
{
if (decl.data()) {
NavigationAction action(DeclarationPointer(decl.data()), NavigationAction::NavigateDeclaration);
return execute(action);
} else {
return NavigationContextPointer(this);
}
}
NavigationContextPointer AbstractNavigationContext::acceptLink(const QString& link)
{
const auto actionIt = d->m_links.constFind(link);
if (actionIt == d->m_links.constEnd()) {
qCDebug(LANGUAGE) << "Executed unregistered link " << link << endl;
return NavigationContextPointer(this);
}
return execute(*actionIt);
}
NavigationAction AbstractNavigationContext::currentAction() const
{
return d->m_selectedLinkAction;
}
QString AbstractNavigationContext::declarationKind(const DeclarationPointer& decl)
{
const auto* function = dynamic_cast(decl.data());
QString kind;
if (decl->isTypeAlias())
kind = i18n("Typedef");
else if (decl->kind() == Declaration::Type) {
if (decl->type())
kind = i18n("Class");
} else if (decl->kind() == Declaration::Instance) {
kind = i18n("Variable");
} else if (decl->kind() == Declaration::Namespace) {
kind = i18n("Namespace");
}
if (auto* alias = dynamic_cast(decl.data())) {
if (alias->identifier().isEmpty())
kind = i18n("Namespace import");
else
kind = i18n("Namespace alias");
}
if (function)
kind = i18n("Function");
if (decl->isForwardDeclaration())
kind = i18n("Forward Declaration");
return kind;
}
QString AbstractNavigationContext::html(bool shorten)
{
d->m_shorten = shorten;
return QString();
}
bool AbstractNavigationContext::alreadyComputed() const
{
return !d->m_currentText.isEmpty();
}
bool AbstractNavigationContext::isWidgetMaximized() const
{
return true;
}
QWidget* AbstractNavigationContext::widget() const
{
return nullptr;
}
///Splits the string by the given regular expression, but keeps the split-matches at the end of each line
static QStringList splitAndKeep(QString str, const QRegExp& regExp)
{
QStringList ret;
int place = regExp.indexIn(str);
while (place != -1) {
ret << str.left(place + regExp.matchedLength());
str.remove(0, place + regExp.matchedLength());
place = regExp.indexIn(str);
}
ret << str;
return ret;
}
void AbstractNavigationContext::addHtml(const QString& html)
{
QRegExp newLineRegExp(QStringLiteral("
|
"));
foreach (const QString& line, splitAndKeep(html, newLineRegExp)) {
d->m_currentText += line;
if (line.indexOf(newLineRegExp) != -1) {
++d->m_currentLine;
if (d->m_currentLine == d->m_currentPositionLine) {
d->m_currentText += QStringLiteral(
" <-> "); // ><-> is <->
}
}
}
}
QString AbstractNavigationContext::currentHtml() const
{
return d->m_currentText;
}
-QString AbstractNavigationContext::fontSizePrefix(bool /*shorten*/) const
-{
- return QString();
-}
-
-QString AbstractNavigationContext::fontSizeSuffix(bool /*shorten*/) const
-{
- return QString();
-}
-
QString Colorizer::operator()(const QString& str) const
{
QString ret = QLatin1String("") + str + QLatin1String("");
if (m_formatting & Fixed)
ret = QLatin1String("") + ret + QLatin1String("");
if (m_formatting & Bold)
ret = QLatin1String("") + ret + QLatin1String("");
if (m_formatting & Italic)
ret = QLatin1String("") + ret + QLatin1String("");
return ret;
}
const Colorizer AbstractNavigationContext::typeHighlight(QStringLiteral("006000"));
const Colorizer AbstractNavigationContext::errorHighlight(QStringLiteral("990000"));
const Colorizer AbstractNavigationContext::labelHighlight(QStringLiteral("000000"));
const Colorizer AbstractNavigationContext::codeHighlight(QStringLiteral("005000"));
const Colorizer AbstractNavigationContext::propertyHighlight(QStringLiteral("009900"));
const Colorizer AbstractNavigationContext::navigationHighlight(QStringLiteral("000099"));
const Colorizer AbstractNavigationContext::importantHighlight(QStringLiteral(
"000000"), Colorizer::Bold | Colorizer::Italic);
const Colorizer AbstractNavigationContext::commentHighlight(QStringLiteral("303030"));
const Colorizer AbstractNavigationContext::nameHighlight(QStringLiteral("000000"), Colorizer::Bold);
}
diff --git a/kdevplatform/language/duchain/navigation/abstractnavigationcontext.h b/kdevplatform/language/duchain/navigation/abstractnavigationcontext.h
index 6583f88d1a..59e2e03b82 100644
--- a/kdevplatform/language/duchain/navigation/abstractnavigationcontext.h
+++ b/kdevplatform/language/duchain/navigation/abstractnavigationcontext.h
@@ -1,185 +1,180 @@
/*
Copyright 2007 David Nolden
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KDEVPLATFORM_ABSTRACTNAVIGATIONCONTEXT_H
#define KDEVPLATFORM_ABSTRACTNAVIGATIONCONTEXT_H
#include
#include
#include "../indexeddeclaration.h"
#include "navigationaction.h"
namespace KDevelop {
/** A helper-class for elegant colorization of html-strings .
*
* Initialize it with a html-color like "990000". and colorize strings
* using operator()
*/
struct KDEVPLATFORMLANGUAGE_EXPORT Colorizer
{
enum FormattingFlag {
Nothing = 0x0,
Bold = 0x1,
Italic = 0x2,
Fixed = 0x4
};
Q_DECLARE_FLAGS(Formatting, FormattingFlag)
explicit Colorizer(const QString& color, Formatting formatting = Nothing)
: m_color(color)
, m_formatting(formatting)
{
}
QString operator()(const QString& str) const;
QString m_color;
Formatting m_formatting;
};
class AbstractNavigationContext;
using NavigationContextPointer = QExplicitlySharedDataPointer;
class KDEVPLATFORMLANGUAGE_EXPORT AbstractNavigationContext
: public QObject
, public QSharedData
{
Q_OBJECT
public:
explicit AbstractNavigationContext(const TopDUContextPointer& topContext = TopDUContextPointer(),
AbstractNavigationContext* previousContext = nullptr);
~AbstractNavigationContext() override;
void nextLink();
void previousLink();
int linkCount() const;
void up();
void down();
QString prefix() const;
QString suffix() const;
void setPrefixSuffix(const QString& prefix, const QString& suffix);
NavigationContextPointer accept();
NavigationContextPointer back();
NavigationContextPointer accept(IndexedDeclaration decl);
NavigationContextPointer acceptLink(const QString& link);
NavigationAction currentAction() const;
virtual QString name() const = 0;
///Here the context can return html to be displayed.
///NOTE: The DUChain must be locked while this is called.
virtual QString html(bool shorten = false);
///Here the context can return a widget to be displayed.
///The widget stays owned by this navigation-context.
///The widget may have a signal "navigateDeclaration(KDevelop::IndexedDeclaration)".
///If that signal is emitted, the new declaration is navigated in the navigation-wdiget.
virtual QWidget* widget() const;
///Whether the widget returned by widget() should take the maximum possible spsace.
///The default implementation returns true.
virtual bool isWidgetMaximized() const;
///Returns whether this context's string has already been computed, and is up to date.
///After clear() was called, this returns false again.
bool alreadyComputed() const;
TopDUContextPointer topContext() const;
void setTopContext(const TopDUContextPointer& context);
void executeLink(const QString& link);
NavigationContextPointer execute(const NavigationAction& action);
Q_SIGNALS:
void contentsChanged();
protected:
- /// Returns the html font-size prefix (aka. <small> or similar) for the given mode
- QString fontSizePrefix(bool shorten) const;
- /// Returns the html font-size suffix (aka. <small> or similar) for the given mode
- QString fontSizeSuffix(bool shorten) const;
-
AbstractNavigationContext* previousContext() const;
virtual void setPreviousContext(AbstractNavigationContext* previousContext);
struct TextHandler
{
explicit TextHandler(AbstractNavigationContext* c) : context(c)
{
}
void operator+=(const QString& str) const
{
context->addHtml(str);
}
AbstractNavigationContext* context;
};
///Override this to execute own key-actions using NavigationAction
virtual NavigationContextPointer executeKeyAction(const QString& key);
///Adds given the text to currentHtml()
void addHtml(const QString& html);
///Returns the html text being built in its current state
QString currentHtml() const;
///Returns a convenience object that allows writing "modifyHtml() += "Hallo";"
TextHandler modifyHtml()
{
return TextHandler(this);
}
//Clears the computed html and links
void clear();
void addExternalHtml(const QString& text);
///Creates and registers a link to the given declaration, labeled by the given name
virtual void makeLink(const QString& name, const DeclarationPointer& declaration,
NavigationAction::Type actionType);
///Creates a link that executes the given action and adds it to the current context
void makeLink(const QString& name, const QString& targetId, const NavigationAction& action);
///Creates a link that executes the given action and returns it
QString createLink(const QString& name, const QString& targetId, const NavigationAction& action);
NavigationContextPointer registerChild(const DeclarationPointer& /*declaration*/);
NavigationContextPointer registerChild(AbstractNavigationContext* context);
virtual QString declarationKind(const DeclarationPointer& decl);
static const Colorizer typeHighlight;
static const Colorizer errorHighlight;
static const Colorizer labelHighlight;
static const Colorizer codeHighlight;
static const Colorizer propertyHighlight;
static const Colorizer navigationHighlight;
static const Colorizer importantHighlight;
static const Colorizer commentHighlight;
static const Colorizer nameHighlight;
private:
const QScopedPointer d;
};
}
Q_DECLARE_OPERATORS_FOR_FLAGS(KDevelop::Colorizer::Formatting)
#endif
diff --git a/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp b/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp
index 9ea5c8ae01..80c18c7c25 100644
--- a/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp
+++ b/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp
@@ -1,70 +1,70 @@
/*
Copyright 2008 David Nolden
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "usesnavigationcontext.h"
#include "useswidget.h"
#include
#include
#include
#include
using namespace KDevelop;
UsesNavigationContext::UsesNavigationContext(IndexedDeclaration declaration, AbstractNavigationContext* previousContext)
: AbstractNavigationContext(TopDUContextPointer(), previousContext)
, m_declaration(declaration)
{
m_widget = new UsesWidget(m_declaration);
}
UsesNavigationContext::~UsesNavigationContext()
{
delete m_widget;
}
QString UsesNavigationContext::name() const
{
return QStringLiteral("Uses");
}
QString UsesNavigationContext::html(bool shorten)
{
clear();
- modifyHtml() += QLatin1String("") + fontSizePrefix(shorten);
+ modifyHtml() += QLatin1String("
");
if (auto context = previousContext()) {
modifyHtml() += navigationHighlight(i18n("Uses of "));
makeLink(context->name(), context->name(), NavigationAction(context));
} else {
KDevelop::DUChainReadLocker lock(DUChain::lock());
if (Declaration* decl = m_declaration.data()) {
makeLink(i18n("Uses of %1", decl->toString()), DeclarationPointer(
decl), NavigationAction::NavigateDeclaration);
}
}
- modifyHtml() += fontSizeSuffix(shorten) + QLatin1String("
");
+ modifyHtml() += QLatin1String("");
return currentHtml();
}
QWidget* UsesNavigationContext::widget() const
{
return m_widget;
}
diff --git a/plugins/clang/duchain/macronavigationcontext.cpp b/plugins/clang/duchain/macronavigationcontext.cpp
index 3c065efdcd..187f44e654 100644
--- a/plugins/clang/duchain/macronavigationcontext.cpp
+++ b/plugins/clang/duchain/macronavigationcontext.cpp
@@ -1,95 +1,95 @@
/*
Copyright 2007 David Nolden
Copyright 2014 Kevin Funk
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "macronavigationcontext.h"
#include "util/clangdebug.h"
#include "util/clangutils.h"
#include
#include
using namespace KDevelop;
MacroNavigationContext::MacroNavigationContext(const MacroDefinition::Ptr& macro,
const KDevelop::DocumentCursor& /* expansionLocation */)
: m_macro(macro)
{
}
MacroNavigationContext::~MacroNavigationContext()
{
}
QString MacroNavigationContext::name() const
{
return m_macro->identifier().toString();
}
QString MacroNavigationContext::html(bool shorten)
{
clear();
- modifyHtml() += QLatin1String("") + fontSizePrefix(shorten);
+ modifyHtml() += QLatin1String("
");
addExternalHtml(prefix());
QStringList parameterList;
parameterList.reserve(m_macro->parametersSize());
FOREACH_FUNCTION(const auto& parameter, m_macro->parameters) {
parameterList << parameter.str();
}
const QString parameters = (!parameterList.isEmpty() ?
QStringLiteral("(%1)").arg(parameterList.join(QStringLiteral(", "))) :
QString());
const QUrl url = m_macro->url().toUrl();
const QString path = url.toLocalFile();
KTextEditor::Cursor cursor(m_macro->rangeInCurrentRevision().start());
NavigationAction action(url, cursor);
modifyHtml() += i18nc("%1: macro type, i.e.: 'Function macro' or just 'Macro'"
"%2: the macro name and arguments",
"%1: %2",
(m_macro->isFunctionLike() ? i18n("Function macro") : i18n("Macro")),
importantHighlight(name()) + parameters);
modifyHtml() += QStringLiteral("
");
modifyHtml() += i18nc("%1: the link to the definition", "Defined in: %1",
createLink(QStringLiteral("%1 :%2").arg(url.fileName()).arg(cursor.line()+1), path, action));
modifyHtml() += QStringLiteral(" "); //The action name _must_ stay "show_uses", since that is also used from outside
makeLink(i18n("Show uses"), QStringLiteral("show_uses"), NavigationAction(m_macro.dynamicCast(), NavigationAction::NavigateUses));
auto code = m_macro->definition().str();
modifyHtml() += QLatin1String("") + i18n("Body: ");
modifyHtml() += QLatin1String("") + code.toHtmlEscaped().replace(QLatin1Char('\n'), QStringLiteral("
")) + QLatin1String("");
modifyHtml() += QStringLiteral("
");
- modifyHtml() += fontSizeSuffix(shorten) + QLatin1String("
");
+ modifyHtml() += QLatin1String("");
return currentHtml();
}
QString MacroNavigationContext::retrievePreprocessedBody(const DocumentCursor& /*expansionLocation*/) const
{
const TopDUContext* topContext = m_macro->topContext();
if (!topContext) {
return QString();
}
// TODO: Implement me. Still not exactly sure what do to here...
return QString();
}