diff --git a/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp b/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp
index 0650b432e0..bbb3b8f1b2 100644
--- a/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp
+++ b/kdevplatform/language/duchain/navigation/abstractdeclarationnavigationcontext.cpp
@@ -1,889 +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);
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("
");
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);
- if (currentArgNum < decls.size()) {
+ // 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[currentArgNum]->identifier().toString().toHtmlEscaped(), d->m_declaration);
+ 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();
}
}