2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
2010-08-13 16:38:45 +02:00
|
|
|
|
|
|
|
|
#include "cppelementevaluator.h"
|
|
|
|
|
|
2021-08-30 10:58:08 +02:00
|
|
|
#include "cppmodelmanager.h"
|
|
|
|
|
#include "cpptoolsreuse.h"
|
|
|
|
|
#include "symbolfinder.h"
|
|
|
|
|
#include "typehierarchybuilder.h"
|
2013-03-27 18:54:03 +01:00
|
|
|
|
2015-02-26 13:22:35 +01:00
|
|
|
#include <texteditor/textdocument.h>
|
|
|
|
|
|
2010-08-13 16:38:45 +02:00
|
|
|
#include <cplusplus/ExpressionUnderCursor.h>
|
2013-03-27 18:54:03 +01:00
|
|
|
#include <cplusplus/Icons.h>
|
|
|
|
|
#include <cplusplus/TypeOfExpression.h>
|
2010-08-13 16:38:45 +02:00
|
|
|
|
2020-11-30 17:02:33 +01:00
|
|
|
#include <utils/runextensions.h>
|
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDir>
|
|
|
|
|
#include <QQueue>
|
2021-08-30 10:58:08 +02:00
|
|
|
#include <QSet>
|
2010-08-13 16:38:45 +02:00
|
|
|
|
|
|
|
|
using namespace CPlusPlus;
|
2022-11-24 13:05:41 +01:00
|
|
|
using namespace Utils;
|
2010-08-13 16:38:45 +02:00
|
|
|
|
2021-09-02 14:52:29 +02:00
|
|
|
namespace CppEditor::Internal {
|
2014-08-27 10:01:27 +02:00
|
|
|
|
|
|
|
|
static QStringList stripName(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
QStringList all;
|
|
|
|
|
all << name;
|
|
|
|
|
int colonColon = 0;
|
|
|
|
|
const int size = name.size();
|
|
|
|
|
while ((colonColon = name.indexOf(QLatin1String("::"), colonColon)) != -1) {
|
|
|
|
|
all << name.right(size - colonColon - 2);
|
|
|
|
|
colonColon += 2;
|
2010-10-01 11:15:28 +02:00
|
|
|
}
|
2014-08-27 10:01:27 +02:00
|
|
|
return all;
|
2010-08-13 16:38:45 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-14 01:40:53 +01:00
|
|
|
CppElement::CppElement() = default;
|
2018-01-19 09:36:46 +01:00
|
|
|
|
2019-01-14 01:40:53 +01:00
|
|
|
CppElement::~CppElement() = default;
|
2018-01-19 09:36:46 +01:00
|
|
|
|
2018-03-08 19:25:04 +01:00
|
|
|
CppClass *CppElement::toCppClass()
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-19 09:36:46 +01:00
|
|
|
class Unknown : public CppElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit Unknown(const QString &type) : type(type)
|
|
|
|
|
{
|
|
|
|
|
tooltip = type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
QString type;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CppInclude : public CppElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppInclude(const Document::Include &includeFile)
|
2022-11-24 13:05:41 +01:00
|
|
|
: path(includeFile.resolvedFileName())
|
|
|
|
|
, fileName(path.fileName())
|
2018-01-19 09:36:46 +01:00
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::Brief;
|
2018-01-19 09:36:46 +01:00
|
|
|
helpIdCandidates = QStringList(fileName);
|
|
|
|
|
helpMark = fileName;
|
2022-11-24 13:05:41 +01:00
|
|
|
link = Utils::Link(path);
|
|
|
|
|
tooltip = path.toUserOutput();
|
2018-01-19 09:36:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
2022-11-24 13:05:41 +01:00
|
|
|
Utils::FilePath path;
|
2018-01-19 09:36:46 +01:00
|
|
|
QString fileName;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CppMacro : public CppElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppMacro(const Macro ¯o)
|
|
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::Macro;
|
2018-01-19 09:36:46 +01:00
|
|
|
const QString macroName = QString::fromUtf8(macro.name(), macro.name().size());
|
|
|
|
|
helpIdCandidates = QStringList(macroName);
|
|
|
|
|
helpMark = macroName;
|
2022-11-23 17:33:36 +01:00
|
|
|
link = Utils::Link(macro.filePath(), macro.line());
|
2018-01-19 09:36:46 +01:00
|
|
|
tooltip = macro.toStringWithLineBreaks();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// CppDeclarableElement
|
|
|
|
|
CppDeclarableElement::CppDeclarableElement(Symbol *declaration)
|
|
|
|
|
: CppElement()
|
2022-12-12 11:07:15 +01:00
|
|
|
, iconType(CPlusPlus::Icons::iconTypeForSymbol(declaration))
|
2018-01-19 09:36:46 +01:00
|
|
|
{
|
|
|
|
|
Overview overview;
|
|
|
|
|
overview.showArgumentNames = true;
|
|
|
|
|
overview.showReturnTypes = true;
|
2021-01-06 15:28:21 +01:00
|
|
|
overview.showTemplateParameters = true;
|
2018-01-19 09:36:46 +01:00
|
|
|
name = overview.prettyName(declaration->name());
|
2022-06-23 16:56:36 +02:00
|
|
|
if (declaration->enclosingScope()->asClass() ||
|
|
|
|
|
declaration->enclosingScope()->asNamespace() ||
|
|
|
|
|
declaration->enclosingScope()->asEnum() ||
|
|
|
|
|
declaration->enclosingScope()->asTemplate()) {
|
2018-01-19 09:36:46 +01:00
|
|
|
qualifiedName = overview.prettyName(LookupContext::fullyQualifiedName(declaration));
|
|
|
|
|
helpIdCandidates = stripName(qualifiedName);
|
|
|
|
|
} else {
|
|
|
|
|
qualifiedName = name;
|
|
|
|
|
helpIdCandidates.append(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tooltip = overview.prettyType(declaration->type(), qualifiedName);
|
2018-02-02 12:52:07 +01:00
|
|
|
link = declaration->toLink();
|
2018-01-19 09:36:46 +01:00
|
|
|
helpMark = name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class CppNamespace : public CppDeclarableElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppNamespace(Symbol *declaration)
|
|
|
|
|
: CppDeclarableElement(declaration)
|
|
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::ClassOrNamespace;
|
2018-01-19 09:36:46 +01:00
|
|
|
tooltip = qualifiedName;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CppClass::CppClass(Symbol *declaration) : CppDeclarableElement(declaration)
|
|
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::ClassOrNamespace;
|
2018-01-19 09:36:46 +01:00
|
|
|
tooltip = qualifiedName;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-08 19:25:04 +01:00
|
|
|
CppClass *CppClass::toCppClass()
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-30 17:02:33 +01:00
|
|
|
void CppClass::lookupBases(QFutureInterfaceBase &futureInterface,
|
|
|
|
|
Symbol *declaration, const LookupContext &context)
|
2018-01-19 09:36:46 +01:00
|
|
|
{
|
2022-12-06 22:41:17 +01:00
|
|
|
ClassOrNamespace *hierarchy = context.lookupType(declaration);
|
|
|
|
|
if (!hierarchy)
|
|
|
|
|
return;
|
|
|
|
|
QSet<ClassOrNamespace *> visited;
|
|
|
|
|
addBaseHierarchy(futureInterface, context, hierarchy, &visited);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CppClass::addBaseHierarchy(QFutureInterfaceBase &futureInterface, const LookupContext &context,
|
|
|
|
|
ClassOrNamespace *hierarchy, QSet<ClassOrNamespace *> *visited)
|
|
|
|
|
{
|
|
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return;
|
|
|
|
|
visited->insert(hierarchy);
|
|
|
|
|
const QList<ClassOrNamespace *> &baseClasses = hierarchy->usings();
|
|
|
|
|
for (ClassOrNamespace *baseClass : baseClasses) {
|
|
|
|
|
const QList<Symbol *> &symbols = baseClass->symbols();
|
|
|
|
|
for (Symbol *symbol : symbols) {
|
|
|
|
|
if (!symbol->asClass())
|
|
|
|
|
continue;
|
|
|
|
|
ClassOrNamespace *baseHierarchy = context.lookupType(symbol);
|
|
|
|
|
if (baseHierarchy && !visited->contains(baseHierarchy)) {
|
|
|
|
|
CppClass classSymbol(symbol);
|
|
|
|
|
classSymbol.addBaseHierarchy(futureInterface, context, baseHierarchy, visited);
|
|
|
|
|
bases.append(classSymbol);
|
2018-01-19 09:36:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-30 17:02:33 +01:00
|
|
|
void CppClass::lookupDerived(QFutureInterfaceBase &futureInterface,
|
|
|
|
|
Symbol *declaration, const Snapshot &snapshot)
|
2018-01-19 09:36:46 +01:00
|
|
|
{
|
2020-12-07 15:19:35 +01:00
|
|
|
snapshot.updateDependencyTable(futureInterface);
|
2020-12-08 09:27:38 +01:00
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return;
|
2022-12-06 22:41:17 +01:00
|
|
|
addDerivedHierarchy(TypeHierarchyBuilder::buildDerivedTypeHierarchy(
|
|
|
|
|
futureInterface, declaration, snapshot));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CppClass::addDerivedHierarchy(const TypeHierarchy &hierarchy)
|
|
|
|
|
{
|
|
|
|
|
CppClass classSymbol(hierarchy.symbol());
|
|
|
|
|
const QList<TypeHierarchy> derivedHierarchies = hierarchy.hierarchy();
|
|
|
|
|
for (const TypeHierarchy &derivedHierarchy : derivedHierarchies)
|
|
|
|
|
classSymbol.addDerivedHierarchy(derivedHierarchy);
|
|
|
|
|
derived.append(classSymbol);
|
2018-01-19 09:36:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class CppFunction : public CppDeclarableElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppFunction(Symbol *declaration)
|
|
|
|
|
: CppDeclarableElement(declaration)
|
|
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::Function;
|
2018-01-19 09:36:46 +01:00
|
|
|
|
|
|
|
|
const FullySpecifiedType &type = declaration->type();
|
|
|
|
|
|
|
|
|
|
// Functions marks can be found either by the main overload or signature based
|
|
|
|
|
// (with no argument names and no return). Help ids have no signature at all.
|
|
|
|
|
Overview overview;
|
|
|
|
|
overview.showDefaultArguments = false;
|
|
|
|
|
helpMark = overview.prettyType(type, name);
|
|
|
|
|
|
|
|
|
|
overview.showFunctionSignatures = false;
|
|
|
|
|
helpIdCandidates.append(overview.prettyName(declaration->name()));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CppEnum : public CppDeclarableElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppEnum(Enum *declaration)
|
|
|
|
|
: CppDeclarableElement(declaration)
|
|
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::Enum;
|
2018-01-19 09:36:46 +01:00
|
|
|
tooltip = qualifiedName;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CppTypedef : public CppDeclarableElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppTypedef(Symbol *declaration)
|
|
|
|
|
: CppDeclarableElement(declaration)
|
|
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::Typedef;
|
2021-01-06 15:28:21 +01:00
|
|
|
Overview overview;
|
|
|
|
|
overview.showTemplateParameters = true;
|
|
|
|
|
tooltip = overview.prettyType(declaration->type(), qualifiedName);
|
2018-01-19 09:36:46 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CppVariable : public CppDeclarableElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppVariable(Symbol *declaration, const LookupContext &context, Scope *scope)
|
|
|
|
|
: CppDeclarableElement(declaration)
|
|
|
|
|
{
|
|
|
|
|
const FullySpecifiedType &type = declaration->type();
|
|
|
|
|
|
2019-01-14 01:40:53 +01:00
|
|
|
const Name *typeName = nullptr;
|
2022-06-24 16:45:12 +02:00
|
|
|
if (type->asNamedType()) {
|
2018-01-19 09:36:46 +01:00
|
|
|
typeName = type->asNamedType()->name();
|
2022-06-24 16:45:12 +02:00
|
|
|
} else if (type->asPointerType() || type->asReferenceType()) {
|
2018-01-19 09:36:46 +01:00
|
|
|
FullySpecifiedType associatedType;
|
2022-06-24 16:45:12 +02:00
|
|
|
if (type->asPointerType())
|
2018-01-19 09:36:46 +01:00
|
|
|
associatedType = type->asPointerType()->elementType();
|
|
|
|
|
else
|
|
|
|
|
associatedType = type->asReferenceType()->elementType();
|
2022-06-24 16:45:12 +02:00
|
|
|
if (associatedType->asNamedType())
|
2018-01-19 09:36:46 +01:00
|
|
|
typeName = associatedType->asNamedType()->name();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeName) {
|
|
|
|
|
if (ClassOrNamespace *clazz = context.lookupType(typeName, scope)) {
|
|
|
|
|
if (!clazz->symbols().isEmpty()) {
|
|
|
|
|
Overview overview;
|
|
|
|
|
Symbol *symbol = clazz->symbols().at(0);
|
|
|
|
|
const QString &name = overview.prettyName(
|
|
|
|
|
LookupContext::fullyQualifiedName(symbol));
|
|
|
|
|
if (!name.isEmpty()) {
|
|
|
|
|
tooltip = name;
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::ClassOrNamespace;
|
2018-01-19 09:36:46 +01:00
|
|
|
const QStringList &allNames = stripName(name);
|
|
|
|
|
if (!allNames.isEmpty()) {
|
|
|
|
|
helpMark = allNames.last();
|
|
|
|
|
helpIdCandidates = allNames;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CppEnumerator : public CppDeclarableElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit CppEnumerator(EnumeratorDeclaration *declaration)
|
|
|
|
|
: CppDeclarableElement(declaration)
|
|
|
|
|
{
|
2019-01-24 11:30:58 +01:00
|
|
|
helpCategory = Core::HelpItem::Enum;
|
2018-01-19 09:36:46 +01:00
|
|
|
|
|
|
|
|
Overview overview;
|
|
|
|
|
|
|
|
|
|
Symbol *enumSymbol = declaration->enclosingScope();
|
|
|
|
|
const QString enumName = overview.prettyName(LookupContext::fullyQualifiedName(enumSymbol));
|
|
|
|
|
const QString enumeratorName = overview.prettyName(declaration->name());
|
|
|
|
|
QString enumeratorValue;
|
|
|
|
|
if (const StringLiteral *value = declaration->constantValue())
|
|
|
|
|
enumeratorValue = QString::fromUtf8(value->chars(), value->size());
|
|
|
|
|
|
|
|
|
|
helpMark = overview.prettyName(enumSymbol->name());
|
|
|
|
|
|
|
|
|
|
tooltip = enumeratorName;
|
|
|
|
|
if (!enumName.isEmpty())
|
|
|
|
|
tooltip.prepend(enumName + QLatin1Char(' '));
|
|
|
|
|
if (!enumeratorValue.isEmpty())
|
|
|
|
|
tooltip.append(QLatin1String(" = ") + enumeratorValue);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
static bool isCppClass(Symbol *symbol)
|
|
|
|
|
{
|
2022-06-23 16:56:36 +02:00
|
|
|
return symbol->asClass() || symbol->asForwardClassDeclaration()
|
|
|
|
|
|| (symbol->asTemplate() && symbol->asTemplate()->declaration()
|
|
|
|
|
&& (symbol->asTemplate()->declaration()->asClass()
|
|
|
|
|
|| symbol->asTemplate()->declaration()->asForwardClassDeclaration()));
|
2021-01-06 15:28:21 +01:00
|
|
|
}
|
2010-08-13 16:38:45 +02:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
static Symbol *followClassDeclaration(Symbol *symbol, const Snapshot &snapshot, SymbolFinder symbolFinder,
|
|
|
|
|
LookupContext *context = nullptr)
|
|
|
|
|
{
|
2022-06-23 16:56:36 +02:00
|
|
|
if (!symbol->asForwardClassDeclaration())
|
2021-01-06 15:28:21 +01:00
|
|
|
return symbol;
|
2010-08-13 16:38:45 +02:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
Symbol *classDeclaration = symbolFinder.findMatchingClassDeclaration(symbol, snapshot);
|
|
|
|
|
if (!classDeclaration)
|
|
|
|
|
return symbol;
|
2011-07-08 09:56:02 +02:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
if (context) {
|
|
|
|
|
const QString fileName = QString::fromUtf8(classDeclaration->fileName(),
|
|
|
|
|
classDeclaration->fileNameLength());
|
|
|
|
|
const Document::Ptr declarationDocument = snapshot.document(fileName);
|
|
|
|
|
if (declarationDocument != context->thisDocument())
|
|
|
|
|
(*context) = LookupContext(declarationDocument, snapshot);
|
|
|
|
|
}
|
|
|
|
|
return classDeclaration;
|
2020-12-18 14:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
static Symbol *followTemplateAsClass(Symbol *symbol)
|
2020-11-30 17:02:33 +01:00
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
if (Template *t = symbol->asTemplate(); t && t->declaration() && t->declaration()->asClass())
|
|
|
|
|
return t->declaration()->asClass();
|
|
|
|
|
return symbol;
|
2020-11-30 17:02:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
static void createTypeHierarchy(QFutureInterface<QSharedPointer<CppElement>> &futureInterface,
|
|
|
|
|
const Snapshot &snapshot,
|
|
|
|
|
const LookupItem &lookupItem,
|
|
|
|
|
const LookupContext &context,
|
|
|
|
|
SymbolFinder symbolFinder)
|
2020-11-30 17:02:33 +01:00
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Symbol *declaration = lookupItem.declaration();
|
|
|
|
|
if (!declaration)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!isCppClass(declaration))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
LookupContext contextToUse = context;
|
|
|
|
|
declaration = followClassDeclaration(declaration, snapshot, symbolFinder, &contextToUse);
|
|
|
|
|
declaration = followTemplateAsClass(declaration);
|
|
|
|
|
|
|
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return;
|
|
|
|
|
QSharedPointer<CppClass> cppClass(new CppClass(declaration));
|
|
|
|
|
cppClass->lookupBases(futureInterface, declaration, contextToUse);
|
|
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return;
|
|
|
|
|
cppClass->lookupDerived(futureInterface, declaration, snapshot);
|
|
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return;
|
|
|
|
|
futureInterface.reportResult(cppClass);
|
2020-11-30 17:02:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
static QSharedPointer<CppElement> handleLookupItemMatch(const Snapshot &snapshot,
|
|
|
|
|
const LookupItem &lookupItem,
|
|
|
|
|
const LookupContext &context,
|
|
|
|
|
SymbolFinder symbolFinder)
|
2020-11-30 17:02:33 +01:00
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
QSharedPointer<CppElement> element;
|
|
|
|
|
Symbol *declaration = lookupItem.declaration();
|
|
|
|
|
if (!declaration) {
|
|
|
|
|
const QString &type = Overview().prettyType(lookupItem.type(), QString());
|
|
|
|
|
element = QSharedPointer<CppElement>(new Unknown(type));
|
|
|
|
|
} else {
|
|
|
|
|
const FullySpecifiedType &type = declaration->type();
|
2022-06-23 16:56:36 +02:00
|
|
|
if (declaration->asNamespace()) {
|
2021-01-06 15:28:21 +01:00
|
|
|
element = QSharedPointer<CppElement>(new CppNamespace(declaration));
|
|
|
|
|
} else if (isCppClass(declaration)) {
|
|
|
|
|
LookupContext contextToUse = context;
|
|
|
|
|
declaration = followClassDeclaration(declaration, snapshot, symbolFinder, &contextToUse);
|
|
|
|
|
element = QSharedPointer<CppElement>(new CppClass(declaration));
|
|
|
|
|
} else if (Enum *enumDecl = declaration->asEnum()) {
|
|
|
|
|
element = QSharedPointer<CppElement>(new CppEnum(enumDecl));
|
|
|
|
|
} else if (auto enumerator = dynamic_cast<EnumeratorDeclaration *>(declaration)) {
|
|
|
|
|
element = QSharedPointer<CppElement>(new CppEnumerator(enumerator));
|
|
|
|
|
} else if (declaration->isTypedef()) {
|
|
|
|
|
element = QSharedPointer<CppElement>(new CppTypedef(declaration));
|
2022-06-23 16:56:36 +02:00
|
|
|
} else if (declaration->asFunction()
|
2022-06-24 16:45:12 +02:00
|
|
|
|| (type.isValid() && type->asFunctionType())
|
2022-06-23 16:56:36 +02:00
|
|
|
|| declaration->asTemplate()) {
|
2021-01-06 15:28:21 +01:00
|
|
|
element = QSharedPointer<CppElement>(new CppFunction(declaration));
|
2022-06-23 16:56:36 +02:00
|
|
|
} else if (declaration->asDeclaration() && type.isValid()) {
|
2021-01-06 15:28:21 +01:00
|
|
|
element = QSharedPointer<CppElement>(
|
|
|
|
|
new CppVariable(declaration, context, lookupItem.scope()));
|
|
|
|
|
} else {
|
|
|
|
|
element = QSharedPointer<CppElement>(new CppDeclarableElement(declaration));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return element;
|
2020-12-18 14:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
// special case for bug QTCREATORBUG-4780
|
|
|
|
|
static bool shouldOmitElement(const LookupItem &lookupItem, const Scope *scope)
|
2020-12-18 14:40:18 +01:00
|
|
|
{
|
2022-06-23 16:56:36 +02:00
|
|
|
return !lookupItem.declaration() && scope && scope->asFunction()
|
2021-01-06 15:28:21 +01:00
|
|
|
&& lookupItem.type().match(scope->asFunction()->returnType());
|
2020-11-30 17:02:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
using namespace std::placeholders;
|
|
|
|
|
using ExecFunction = std::function<QFuture<QSharedPointer<CppElement>>
|
|
|
|
|
(const CPlusPlus::Snapshot &, const CPlusPlus::LookupItem &,
|
|
|
|
|
const CPlusPlus::LookupContext &)>;
|
|
|
|
|
using SourceFunction = std::function<bool(const CPlusPlus::Snapshot &,
|
|
|
|
|
CPlusPlus::Document::Ptr &,
|
|
|
|
|
CPlusPlus::Scope **, QString &)>;
|
|
|
|
|
|
2020-11-30 17:02:33 +01:00
|
|
|
static QFuture<QSharedPointer<CppElement>> createFinishedFuture()
|
|
|
|
|
{
|
|
|
|
|
QFutureInterface<QSharedPointer<CppElement>> futureInterface;
|
|
|
|
|
futureInterface.reportStarted();
|
|
|
|
|
futureInterface.reportFinished();
|
|
|
|
|
return futureInterface.future();
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
static LookupItem findLookupItem(const CPlusPlus::Snapshot &snapshot, CPlusPlus::Document::Ptr &doc,
|
|
|
|
|
Scope *scope, const QString &expression, LookupContext *lookupContext, bool followTypedef)
|
2020-12-18 14:40:18 +01:00
|
|
|
{
|
2020-11-30 17:02:33 +01:00
|
|
|
TypeOfExpression typeOfExpression;
|
|
|
|
|
typeOfExpression.init(doc, snapshot);
|
|
|
|
|
// make possible to instantiate templates
|
|
|
|
|
typeOfExpression.setExpandTemplates(true);
|
|
|
|
|
const QList<LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope);
|
2021-01-06 15:28:21 +01:00
|
|
|
*lookupContext = typeOfExpression.context();
|
2020-11-30 17:02:33 +01:00
|
|
|
if (lookupItems.isEmpty())
|
2021-01-06 15:28:21 +01:00
|
|
|
return LookupItem();
|
2020-11-30 17:02:33 +01:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
auto isInteresting = [followTypedef](Symbol *symbol) {
|
2022-06-23 16:56:36 +02:00
|
|
|
return symbol && (!followTypedef || (symbol->asClass() || symbol->asTemplate()
|
|
|
|
|
|| symbol->asForwardClassDeclaration() || symbol->isTypedef()));
|
2021-01-06 15:28:21 +01:00
|
|
|
};
|
2020-12-22 08:29:18 +01:00
|
|
|
|
|
|
|
|
for (const LookupItem &item : lookupItems) {
|
|
|
|
|
if (shouldOmitElement(item, scope))
|
|
|
|
|
continue;
|
|
|
|
|
Symbol *symbol = item.declaration();
|
2021-01-06 15:28:21 +01:00
|
|
|
if (!isInteresting(symbol))
|
2020-12-22 08:29:18 +01:00
|
|
|
continue;
|
2021-01-06 15:28:21 +01:00
|
|
|
if (followTypedef && symbol->isTypedef()) {
|
2021-01-05 10:15:36 +01:00
|
|
|
CPlusPlus::NamedType *namedType = symbol->type()->asNamedType();
|
|
|
|
|
if (!namedType) {
|
|
|
|
|
// Anonymous aggregate such as: typedef struct {} Empty;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-01-06 15:28:21 +01:00
|
|
|
return TypeHierarchyBuilder::followTypedef(*lookupContext,
|
2021-01-05 10:15:36 +01:00
|
|
|
namedType->name(), symbol->enclosingScope());
|
|
|
|
|
}
|
2021-01-06 15:28:21 +01:00
|
|
|
return item;
|
2020-12-22 08:29:18 +01:00
|
|
|
}
|
2021-01-06 15:28:21 +01:00
|
|
|
return LookupItem();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QFuture<QSharedPointer<CppElement>> exec(SourceFunction &&sourceFunction,
|
|
|
|
|
ExecFunction &&execFunction,
|
|
|
|
|
bool followTypedef = true)
|
|
|
|
|
{
|
|
|
|
|
const Snapshot &snapshot = CppModelManager::instance()->snapshot();
|
|
|
|
|
|
|
|
|
|
Document::Ptr doc;
|
|
|
|
|
QString expression;
|
|
|
|
|
Scope *scope = nullptr;
|
|
|
|
|
if (!std::invoke(std::forward<SourceFunction>(sourceFunction), snapshot, doc, &scope, expression))
|
|
|
|
|
return createFinishedFuture();
|
2020-12-22 08:29:18 +01:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
LookupContext lookupContext;
|
|
|
|
|
const LookupItem &lookupItem = findLookupItem(snapshot, doc, scope, expression, &lookupContext,
|
|
|
|
|
followTypedef);
|
2020-12-22 08:29:18 +01:00
|
|
|
if (!lookupItem.declaration())
|
2020-11-30 17:02:33 +01:00
|
|
|
return createFinishedFuture();
|
2020-12-22 08:29:18 +01:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
return std::invoke(std::forward<ExecFunction>(execFunction), snapshot, lookupItem, lookupContext);
|
2020-11-30 17:02:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
static QFuture<QSharedPointer<CppElement>> asyncExec(
|
2020-11-30 17:02:33 +01:00
|
|
|
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::LookupItem &lookupItem,
|
|
|
|
|
const CPlusPlus::LookupContext &lookupContext)
|
|
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
return Utils::runAsync(&createTypeHierarchy, snapshot, lookupItem, lookupContext,
|
|
|
|
|
*CppModelManager::instance()->symbolFinder());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class FromExpressionFunctor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FromExpressionFunctor(const QString &expression, const QString &fileName)
|
|
|
|
|
: m_expression(expression)
|
|
|
|
|
, m_fileName(fileName)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
bool operator()(const CPlusPlus::Snapshot &snapshot, Document::Ptr &doc, Scope **scope,
|
|
|
|
|
QString &expression)
|
|
|
|
|
{
|
|
|
|
|
doc = snapshot.document(m_fileName);
|
2021-01-27 11:50:15 +01:00
|
|
|
if (doc.isNull())
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
expression = m_expression;
|
|
|
|
|
|
|
|
|
|
// Fetch the expression's code
|
|
|
|
|
*scope = doc->globalNamespace();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
const QString m_expression;
|
|
|
|
|
const QString m_fileName;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QFuture<QSharedPointer<CppElement>> CppElementEvaluator::asyncExecute(const QString &expression,
|
|
|
|
|
const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
return exec(FromExpressionFunctor(expression, fileName), asyncExec);
|
2020-11-30 17:02:33 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
class FromGuiFunctor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FromGuiFunctor(TextEditor::TextEditorWidget *editor)
|
|
|
|
|
: m_editor(editor)
|
|
|
|
|
, m_tc(editor->textCursor())
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
bool operator()(const CPlusPlus::Snapshot &snapshot, Document::Ptr &doc, Scope **scope,
|
|
|
|
|
QString &expression)
|
|
|
|
|
{
|
|
|
|
|
doc = snapshot.document(m_editor->textDocument()->filePath());
|
|
|
|
|
if (!doc)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
int line = 0;
|
|
|
|
|
int column = 0;
|
|
|
|
|
const int pos = m_tc.position();
|
|
|
|
|
m_editor->convertPosition(pos, &line, &column);
|
|
|
|
|
|
|
|
|
|
checkDiagnosticMessage(pos);
|
|
|
|
|
|
|
|
|
|
if (matchIncludeFile(doc, line) || matchMacroInUse(doc, pos))
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-08-30 10:58:08 +02:00
|
|
|
moveCursorToEndOfIdentifier(&m_tc);
|
2021-01-06 15:28:21 +01:00
|
|
|
ExpressionUnderCursor expressionUnderCursor(doc->languageFeatures());
|
|
|
|
|
expression = expressionUnderCursor(m_tc);
|
|
|
|
|
|
|
|
|
|
// Fetch the expression's code
|
|
|
|
|
*scope = doc->scopeAt(line, column - 1);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
QFuture<QSharedPointer<CppElement>> syncExec(const CPlusPlus::Snapshot &,
|
|
|
|
|
const CPlusPlus::LookupItem &, const CPlusPlus::LookupContext &);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void checkDiagnosticMessage(int pos);
|
|
|
|
|
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, int line);
|
|
|
|
|
bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, int pos);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
void clear();
|
|
|
|
|
|
|
|
|
|
TextEditor::TextEditorWidget *m_editor;
|
|
|
|
|
QTextCursor m_tc;
|
|
|
|
|
QSharedPointer<CppElement> m_element;
|
|
|
|
|
QString m_diagnosis;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QFuture<QSharedPointer<CppElement>> FromGuiFunctor::syncExec(
|
2020-11-30 17:02:33 +01:00
|
|
|
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::LookupItem &lookupItem,
|
|
|
|
|
const CPlusPlus::LookupContext &lookupContext)
|
|
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
QFutureInterface<QSharedPointer<CppElement>> futureInterface;
|
|
|
|
|
futureInterface.reportStarted();
|
|
|
|
|
m_element = handleLookupItemMatch(snapshot, lookupItem, lookupContext,
|
|
|
|
|
*CppModelManager::instance()->symbolFinder());
|
|
|
|
|
futureInterface.reportResult(m_element);
|
|
|
|
|
futureInterface.reportFinished();
|
|
|
|
|
return futureInterface.future();
|
2010-08-13 16:38:45 +02:00
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
void FromGuiFunctor::checkDiagnosticMessage(int pos)
|
2010-08-13 16:38:45 +02:00
|
|
|
{
|
2022-05-05 15:51:12 +02:00
|
|
|
const QList<QTextEdit::ExtraSelection> &selections = m_editor->extraSelections(
|
|
|
|
|
TextEditor::TextEditorWidget::CodeWarningsSelection);
|
|
|
|
|
for (const QTextEdit::ExtraSelection &sel : selections) {
|
2011-08-24 12:01:50 +02:00
|
|
|
if (pos >= sel.cursor.selectionStart() && pos <= sel.cursor.selectionEnd()) {
|
|
|
|
|
m_diagnosis = sel.format.toolTip();
|
2011-01-17 16:29:57 +01:00
|
|
|
break;
|
2010-08-13 16:38:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
bool FromGuiFunctor::matchIncludeFile(const Document::Ptr &document, int line)
|
2010-08-13 16:38:45 +02:00
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
const QList<Document::Include> &includes = document->resolvedIncludes();
|
|
|
|
|
for (const Document::Include &includeFile : includes) {
|
2010-08-13 16:38:45 +02:00
|
|
|
if (includeFile.line() == line) {
|
|
|
|
|
m_element = QSharedPointer<CppElement>(new CppInclude(includeFile));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
bool FromGuiFunctor::matchMacroInUse(const Document::Ptr &document, int pos)
|
2010-08-13 16:38:45 +02:00
|
|
|
{
|
2022-08-10 09:41:42 +02:00
|
|
|
for (const Document::MacroUse &use : document->macroUses()) {
|
2014-05-09 10:04:13 -04:00
|
|
|
if (use.containsUtf16charOffset(pos)) {
|
2019-07-24 18:40:10 +02:00
|
|
|
const int begin = use.utf16charsBegin();
|
2014-05-09 10:04:13 -04:00
|
|
|
if (pos < begin + use.macro().nameToQString().size()) {
|
2010-08-13 16:38:45 +02:00
|
|
|
m_element = QSharedPointer<CppElement>(new CppMacro(use.macro()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
void FromGuiFunctor::clear()
|
2010-08-13 16:38:45 +02:00
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
m_element.clear();
|
|
|
|
|
m_diagnosis.clear();
|
|
|
|
|
}
|
2013-11-19 18:12:20 +01:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
class CppElementEvaluatorPrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CppElementEvaluatorPrivate(TextEditor::TextEditorWidget *editor) : m_functor(editor) {}
|
|
|
|
|
FromGuiFunctor m_functor;
|
|
|
|
|
};
|
2020-12-22 08:29:18 +01:00
|
|
|
|
2021-01-06 15:28:21 +01:00
|
|
|
CppElementEvaluator::CppElementEvaluator(TextEditor::TextEditorWidget *editor)
|
|
|
|
|
: d(new CppElementEvaluatorPrivate(editor))
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
CppElementEvaluator::~CppElementEvaluator()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CppElementEvaluator::setTextCursor(const QTextCursor &tc)
|
|
|
|
|
{
|
|
|
|
|
d->m_functor.m_tc = tc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QFuture<QSharedPointer<CppElement>> CppElementEvaluator::asyncExecute(
|
|
|
|
|
TextEditor::TextEditorWidget *editor)
|
|
|
|
|
{
|
|
|
|
|
return exec(FromGuiFunctor(editor), asyncExec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CppElementEvaluator::execute()
|
|
|
|
|
{
|
|
|
|
|
d->m_functor.clear();
|
|
|
|
|
exec(std::ref(d->m_functor), std::bind(&FromGuiFunctor::syncExec, &d->m_functor, _1, _2, _3), false);
|
2010-08-13 16:38:45 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-17 16:29:57 +01:00
|
|
|
bool CppElementEvaluator::identifiedCppElement() const
|
|
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
return !d->m_functor.m_element.isNull();
|
2011-01-17 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QSharedPointer<CppElement> &CppElementEvaluator::cppElement() const
|
|
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
return d->m_functor.m_element;
|
2011-01-17 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CppElementEvaluator::hasDiagnosis() const
|
|
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
return !d->m_functor.m_diagnosis.isEmpty();
|
2011-01-17 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QString &CppElementEvaluator::diagnosis() const
|
|
|
|
|
{
|
2021-01-06 15:28:21 +01:00
|
|
|
return d->m_functor.m_diagnosis;
|
2011-01-17 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-18 14:40:18 +01:00
|
|
|
Utils::Link CppElementEvaluator::linkFromExpression(const QString &expression, const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
const Snapshot &snapshot = CppModelManager::instance()->snapshot();
|
|
|
|
|
Document::Ptr doc = snapshot.document(fileName);
|
2021-01-27 11:50:15 +01:00
|
|
|
if (doc.isNull())
|
|
|
|
|
return Utils::Link();
|
2020-12-18 14:40:18 +01:00
|
|
|
Scope *scope = doc->globalNamespace();
|
|
|
|
|
|
|
|
|
|
TypeOfExpression typeOfExpression;
|
|
|
|
|
typeOfExpression.init(doc, snapshot);
|
|
|
|
|
typeOfExpression.setExpandTemplates(true);
|
|
|
|
|
const QList<LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope);
|
|
|
|
|
if (lookupItems.isEmpty())
|
|
|
|
|
return Utils::Link();
|
|
|
|
|
|
|
|
|
|
for (const LookupItem &item : lookupItems) {
|
|
|
|
|
Symbol *symbol = item.declaration();
|
|
|
|
|
if (!symbol)
|
|
|
|
|
continue;
|
2022-06-23 16:56:36 +02:00
|
|
|
if (!symbol->asClass() && !symbol->asTemplate())
|
2020-12-18 14:40:18 +01:00
|
|
|
continue;
|
|
|
|
|
return symbol->toLink();
|
|
|
|
|
}
|
|
|
|
|
return Utils::Link();
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-02 14:52:29 +02:00
|
|
|
} // namespace CppEditor::Internal
|