forked from qt-creator/qt-creator
CppTools: Move CppHoverHandler to CppTools
This is in preparation for clang code model to provide its own hover handler. Change-Id: Ifbdd96f427989bd5d1fbc4badb9c38108485c2f2 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
473
src/plugins/cpptools/cppelementevaluator.cpp
Normal file
473
src/plugins/cpptools/cppelementevaluator.cpp
Normal file
@@ -0,0 +1,473 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "cppelementevaluator.h"
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <cpptools/symbolfinder.h>
|
||||
#include <cpptools/typehierarchybuilder.h>
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
|
||||
#include <cplusplus/ExpressionUnderCursor.h>
|
||||
#include <cplusplus/Icons.h>
|
||||
#include <cplusplus/TypeOfExpression.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QSet>
|
||||
#include <QQueue>
|
||||
|
||||
using namespace CPlusPlus;
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
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;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
CppElementEvaluator::CppElementEvaluator(TextEditor::TextEditorWidget *editor) :
|
||||
m_editor(editor),
|
||||
m_modelManager(CppTools::CppModelManager::instance()),
|
||||
m_tc(editor->textCursor()),
|
||||
m_lookupBaseClasses(false),
|
||||
m_lookupDerivedClasses(false)
|
||||
{}
|
||||
|
||||
void CppElementEvaluator::setTextCursor(const QTextCursor &tc)
|
||||
{ m_tc = tc; }
|
||||
|
||||
void CppElementEvaluator::setLookupBaseClasses(const bool lookup)
|
||||
{ m_lookupBaseClasses = lookup; }
|
||||
|
||||
void CppElementEvaluator::setLookupDerivedClasses(const bool lookup)
|
||||
{ m_lookupDerivedClasses = lookup; }
|
||||
|
||||
// @todo: Consider refactoring code from CppEditor::findLinkAt into here.
|
||||
void CppElementEvaluator::execute()
|
||||
{
|
||||
clear();
|
||||
|
||||
if (!m_modelManager)
|
||||
return;
|
||||
|
||||
const Snapshot &snapshot = m_modelManager->snapshot();
|
||||
Document::Ptr doc = snapshot.document(m_editor->textDocument()->filePath());
|
||||
if (!doc)
|
||||
return;
|
||||
|
||||
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)) {
|
||||
CppTools::moveCursorToEndOfIdentifier(&m_tc);
|
||||
|
||||
// Fetch the expression's code
|
||||
ExpressionUnderCursor expressionUnderCursor(doc->languageFeatures());
|
||||
const QString &expression = expressionUnderCursor(m_tc);
|
||||
Scope *scope = doc->scopeAt(line, column);
|
||||
|
||||
TypeOfExpression typeOfExpression;
|
||||
typeOfExpression.init(doc, snapshot);
|
||||
// make possible to instantiate templates
|
||||
typeOfExpression.setExpandTemplates(true);
|
||||
const QList<LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope);
|
||||
if (lookupItems.isEmpty())
|
||||
return;
|
||||
|
||||
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate.
|
||||
handleLookupItemMatch(snapshot, lookupItem, typeOfExpression.context(), scope);
|
||||
}
|
||||
}
|
||||
|
||||
void CppElementEvaluator::checkDiagnosticMessage(int pos)
|
||||
{
|
||||
foreach (const QTextEdit::ExtraSelection &sel,
|
||||
m_editor->extraSelections(TextEditor::TextEditorWidget::CodeWarningsSelection)) {
|
||||
if (pos >= sel.cursor.selectionStart() && pos <= sel.cursor.selectionEnd()) {
|
||||
m_diagnosis = sel.format.toolTip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CppElementEvaluator::matchIncludeFile(const Document::Ptr &document, unsigned line)
|
||||
{
|
||||
foreach (const Document::Include &includeFile, document->resolvedIncludes()) {
|
||||
if (includeFile.line() == line) {
|
||||
m_element = QSharedPointer<CppElement>(new CppInclude(includeFile));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CppElementEvaluator::matchMacroInUse(const Document::Ptr &document, unsigned pos)
|
||||
{
|
||||
foreach (const Document::MacroUse &use, document->macroUses()) {
|
||||
if (use.containsUtf16charOffset(pos)) {
|
||||
const unsigned begin = use.utf16charsBegin();
|
||||
if (pos < begin + use.macro().nameToQString().size()) {
|
||||
m_element = QSharedPointer<CppElement>(new CppMacro(use.macro()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
|
||||
const LookupItem &lookupItem,
|
||||
const LookupContext &context,
|
||||
const Scope *scope)
|
||||
{
|
||||
Symbol *declaration = lookupItem.declaration();
|
||||
if (!declaration) {
|
||||
const QString &type = Overview().prettyType(lookupItem.type(), QString());
|
||||
// special case for bug QTCREATORBUG-4780
|
||||
if (scope && scope->isFunction()
|
||||
&& lookupItem.type().match(scope->asFunction()->returnType())) {
|
||||
return;
|
||||
}
|
||||
m_element = QSharedPointer<CppElement>(new Unknown(type));
|
||||
} else {
|
||||
const FullySpecifiedType &type = declaration->type();
|
||||
if (declaration->isNamespace()) {
|
||||
m_element = QSharedPointer<CppElement>(new CppNamespace(declaration));
|
||||
} else if (declaration->isClass()
|
||||
|| declaration->isForwardClassDeclaration()
|
||||
|| (declaration->isTemplate() && declaration->asTemplate()->declaration()
|
||||
&& (declaration->asTemplate()->declaration()->isClass()
|
||||
|| declaration->asTemplate()->declaration()->isForwardClassDeclaration()))) {
|
||||
LookupContext contextToUse = context;
|
||||
if (declaration->isForwardClassDeclaration()) {
|
||||
const auto symbolFinder = m_modelManager->symbolFinder();
|
||||
Symbol *classDeclaration = symbolFinder->findMatchingClassDeclaration(declaration,
|
||||
snapshot);
|
||||
if (classDeclaration) {
|
||||
declaration = classDeclaration;
|
||||
const QString fileName = QString::fromUtf8(declaration->fileName(),
|
||||
declaration->fileNameLength());
|
||||
const Document::Ptr declarationDocument = snapshot.document(fileName);
|
||||
if (declarationDocument != context.thisDocument())
|
||||
contextToUse = LookupContext(declarationDocument, snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
CppClass *cppClass = new CppClass(declaration);
|
||||
if (m_lookupBaseClasses)
|
||||
cppClass->lookupBases(declaration, contextToUse);
|
||||
if (m_lookupDerivedClasses)
|
||||
cppClass->lookupDerived(declaration, snapshot);
|
||||
m_element = QSharedPointer<CppElement>(cppClass);
|
||||
} else if (Enum *enumDecl = declaration->asEnum()) {
|
||||
m_element = QSharedPointer<CppElement>(new CppEnum(enumDecl));
|
||||
} else if (EnumeratorDeclaration *enumerator = dynamic_cast<EnumeratorDeclaration *>(declaration)) {
|
||||
m_element = QSharedPointer<CppElement>(new CppEnumerator(enumerator));
|
||||
} else if (declaration->isTypedef()) {
|
||||
m_element = QSharedPointer<CppElement>(new CppTypedef(declaration));
|
||||
} else if (declaration->isFunction()
|
||||
|| (type.isValid() && type->isFunctionType())
|
||||
|| declaration->isTemplate()) {
|
||||
m_element = QSharedPointer<CppElement>(new CppFunction(declaration));
|
||||
} else if (declaration->isDeclaration() && type.isValid()) {
|
||||
m_element = QSharedPointer<CppElement>(
|
||||
new CppVariable(declaration, context, lookupItem.scope()));
|
||||
} else {
|
||||
m_element = QSharedPointer<CppElement>(new CppDeclarableElement(declaration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CppElementEvaluator::identifiedCppElement() const
|
||||
{
|
||||
return !m_element.isNull();
|
||||
}
|
||||
|
||||
const QSharedPointer<CppElement> &CppElementEvaluator::cppElement() const
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
bool CppElementEvaluator::hasDiagnosis() const
|
||||
{
|
||||
return !m_diagnosis.isEmpty();
|
||||
}
|
||||
|
||||
const QString &CppElementEvaluator::diagnosis() const
|
||||
{
|
||||
return m_diagnosis;
|
||||
}
|
||||
|
||||
void CppElementEvaluator::clear()
|
||||
{
|
||||
m_element.clear();
|
||||
m_diagnosis.clear();
|
||||
}
|
||||
|
||||
// CppElement
|
||||
CppElement::CppElement() : helpCategory(TextEditor::HelpItem::Unknown)
|
||||
{}
|
||||
|
||||
CppElement::~CppElement()
|
||||
{}
|
||||
|
||||
// Unknown
|
||||
Unknown::Unknown(const QString &type) : type(type)
|
||||
{
|
||||
tooltip = type;
|
||||
}
|
||||
|
||||
|
||||
// CppInclude
|
||||
|
||||
CppInclude::CppInclude(const Document::Include &includeFile) :
|
||||
path(QDir::toNativeSeparators(includeFile.resolvedFileName())),
|
||||
fileName(Utils::FileName::fromString(includeFile.resolvedFileName()).fileName())
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::Brief;
|
||||
helpIdCandidates = QStringList(fileName);
|
||||
helpMark = fileName;
|
||||
link = Utils::Link(path);
|
||||
tooltip = path;
|
||||
}
|
||||
|
||||
// CppMacro
|
||||
CppMacro::CppMacro(const Macro ¯o)
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::Macro;
|
||||
const QString macroName = QString::fromUtf8(macro.name(), macro.name().size());
|
||||
helpIdCandidates = QStringList(macroName);
|
||||
helpMark = macroName;
|
||||
link = Utils::Link(macro.fileName(), macro.line());
|
||||
tooltip = macro.toStringWithLineBreaks();
|
||||
}
|
||||
|
||||
// CppDeclarableElement
|
||||
|
||||
CppDeclarableElement::CppDeclarableElement(Symbol *declaration)
|
||||
: CppElement()
|
||||
, declaration(declaration)
|
||||
, icon(Icons::iconForSymbol(declaration))
|
||||
{
|
||||
Overview overview;
|
||||
overview.showArgumentNames = true;
|
||||
overview.showReturnTypes = true;
|
||||
name = overview.prettyName(declaration->name());
|
||||
if (declaration->enclosingScope()->isClass() ||
|
||||
declaration->enclosingScope()->isNamespace() ||
|
||||
declaration->enclosingScope()->isEnum()) {
|
||||
qualifiedName = overview.prettyName(LookupContext::fullyQualifiedName(declaration));
|
||||
helpIdCandidates = stripName(qualifiedName);
|
||||
} else {
|
||||
qualifiedName = name;
|
||||
helpIdCandidates.append(name);
|
||||
}
|
||||
|
||||
tooltip = overview.prettyType(declaration->type(), qualifiedName);
|
||||
link = CppTools::linkToSymbol(declaration);
|
||||
helpMark = name;
|
||||
}
|
||||
|
||||
// CppNamespace
|
||||
CppNamespace::CppNamespace(Symbol *declaration) : CppDeclarableElement(declaration)
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::ClassOrNamespace;
|
||||
tooltip = qualifiedName;
|
||||
}
|
||||
|
||||
// CppClass
|
||||
CppClass::CppClass(Symbol *declaration) : CppDeclarableElement(declaration)
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::ClassOrNamespace;
|
||||
tooltip = qualifiedName;
|
||||
}
|
||||
|
||||
bool CppClass::operator==(const CppClass &other)
|
||||
{
|
||||
return this->declaration == other.declaration;
|
||||
}
|
||||
|
||||
void CppClass::lookupBases(Symbol *declaration, const LookupContext &context)
|
||||
{
|
||||
typedef QPair<ClassOrNamespace *, CppClass *> Data;
|
||||
|
||||
if (ClassOrNamespace *clazz = context.lookupType(declaration)) {
|
||||
QSet<ClassOrNamespace *> visited;
|
||||
|
||||
QQueue<Data> q;
|
||||
q.enqueue(qMakePair(clazz, this));
|
||||
while (!q.isEmpty()) {
|
||||
Data current = q.dequeue();
|
||||
clazz = current.first;
|
||||
visited.insert(clazz);
|
||||
const QList<ClassOrNamespace *> &bases = clazz->usings();
|
||||
foreach (ClassOrNamespace *baseClass, bases) {
|
||||
const QList<Symbol *> &symbols = baseClass->symbols();
|
||||
foreach (Symbol *symbol, symbols) {
|
||||
if (symbol->isClass() && (
|
||||
clazz = context.lookupType(symbol)) &&
|
||||
!visited.contains(clazz)) {
|
||||
CppClass baseCppClass(symbol);
|
||||
CppClass *cppClass = current.second;
|
||||
cppClass->bases.append(baseCppClass);
|
||||
q.enqueue(qMakePair(clazz, &cppClass->bases.last()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppClass::lookupDerived(Symbol *declaration, const Snapshot &snapshot)
|
||||
{
|
||||
typedef QPair<CppClass *, CppTools::TypeHierarchy> Data;
|
||||
|
||||
CppTools::TypeHierarchyBuilder builder(declaration, snapshot);
|
||||
const CppTools::TypeHierarchy &completeHierarchy = builder.buildDerivedTypeHierarchy();
|
||||
|
||||
QQueue<Data> q;
|
||||
q.enqueue(qMakePair(this, completeHierarchy));
|
||||
while (!q.isEmpty()) {
|
||||
const Data ¤t = q.dequeue();
|
||||
CppClass *clazz = current.first;
|
||||
const CppTools::TypeHierarchy &classHierarchy = current.second;
|
||||
foreach (const CppTools::TypeHierarchy &derivedHierarchy, classHierarchy.hierarchy()) {
|
||||
clazz->derived.append(CppClass(derivedHierarchy.symbol()));
|
||||
q.enqueue(qMakePair(&clazz->derived.last(), derivedHierarchy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CppFunction
|
||||
CppFunction::CppFunction(Symbol *declaration)
|
||||
: CppDeclarableElement(declaration)
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::Function;
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
// CppEnum
|
||||
CppEnum::CppEnum(Enum *declaration)
|
||||
: CppDeclarableElement(declaration)
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::Enum;
|
||||
tooltip = qualifiedName;
|
||||
}
|
||||
|
||||
// CppTypedef
|
||||
CppTypedef::CppTypedef(Symbol *declaration) : CppDeclarableElement(declaration)
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::Typedef;
|
||||
tooltip = Overview().prettyType(declaration->type(), qualifiedName);
|
||||
}
|
||||
|
||||
// CppVariable
|
||||
CppVariable::CppVariable(Symbol *declaration, const LookupContext &context, Scope *scope) :
|
||||
CppDeclarableElement(declaration)
|
||||
{
|
||||
const FullySpecifiedType &type = declaration->type();
|
||||
|
||||
const Name *typeName = 0;
|
||||
if (type->isNamedType()) {
|
||||
typeName = type->asNamedType()->name();
|
||||
} else if (type->isPointerType() || type->isReferenceType()) {
|
||||
FullySpecifiedType associatedType;
|
||||
if (type->isPointerType())
|
||||
associatedType = type->asPointerType()->elementType();
|
||||
else
|
||||
associatedType = type->asReferenceType()->elementType();
|
||||
if (associatedType->isNamedType())
|
||||
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;
|
||||
helpCategory = TextEditor::HelpItem::ClassOrNamespace;
|
||||
const QStringList &allNames = stripName(name);
|
||||
if (!allNames.isEmpty()) {
|
||||
helpMark = allNames.last();
|
||||
helpIdCandidates = allNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CppEnumerator::CppEnumerator(EnumeratorDeclaration *declaration)
|
||||
: CppDeclarableElement(declaration)
|
||||
{
|
||||
helpCategory = TextEditor::HelpItem::Enum;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace CppTools
|
||||
191
src/plugins/cpptools/cppelementevaluator.h
Normal file
191
src/plugins/cpptools/cppelementevaluator.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpptools_global.h"
|
||||
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/helpitem.h>
|
||||
|
||||
#include <cplusplus/CppDocument.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QSharedPointer>
|
||||
#include <QTextCursor>
|
||||
#include <QIcon>
|
||||
|
||||
namespace CPlusPlus {
|
||||
class LookupItem;
|
||||
class LookupContext;
|
||||
}
|
||||
|
||||
namespace CppTools {
|
||||
class CppElement;
|
||||
class CppModelManager;
|
||||
|
||||
class CPPTOOLS_EXPORT CppElementEvaluator
|
||||
{
|
||||
public:
|
||||
explicit CppElementEvaluator(TextEditor::TextEditorWidget *editor);
|
||||
|
||||
void setTextCursor(const QTextCursor &tc);
|
||||
void setLookupBaseClasses(const bool lookup);
|
||||
void setLookupDerivedClasses(const bool lookup);
|
||||
|
||||
void execute();
|
||||
bool identifiedCppElement() const;
|
||||
const QSharedPointer<CppElement> &cppElement() const;
|
||||
bool hasDiagnosis() const;
|
||||
const QString &diagnosis() const;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
void checkDiagnosticMessage(int pos);
|
||||
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, unsigned line);
|
||||
bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, unsigned pos);
|
||||
void handleLookupItemMatch(const CPlusPlus::Snapshot &snapshot,
|
||||
const CPlusPlus::LookupItem &lookupItem,
|
||||
const CPlusPlus::LookupContext &lookupContext,
|
||||
const CPlusPlus::Scope *scope);
|
||||
|
||||
TextEditor::TextEditorWidget *m_editor;
|
||||
CppTools::CppModelManager *m_modelManager;
|
||||
QTextCursor m_tc;
|
||||
bool m_lookupBaseClasses;
|
||||
bool m_lookupDerivedClasses;
|
||||
QSharedPointer<CppElement> m_element;
|
||||
QString m_diagnosis;
|
||||
};
|
||||
|
||||
class CPPTOOLS_EXPORT CppElement
|
||||
{
|
||||
protected:
|
||||
CppElement();
|
||||
|
||||
public:
|
||||
virtual ~CppElement();
|
||||
|
||||
TextEditor::HelpItem::Category helpCategory;
|
||||
QStringList helpIdCandidates;
|
||||
QString helpMark;
|
||||
Utils::Link link;
|
||||
QString tooltip;
|
||||
};
|
||||
|
||||
class Unknown : public CppElement
|
||||
{
|
||||
public:
|
||||
explicit Unknown(const QString &type);
|
||||
|
||||
public:
|
||||
QString type;
|
||||
};
|
||||
|
||||
class CppInclude : public CppElement
|
||||
{
|
||||
public:
|
||||
explicit CppInclude(const CPlusPlus::Document::Include &includeFile);
|
||||
|
||||
public:
|
||||
QString path;
|
||||
QString fileName;
|
||||
};
|
||||
|
||||
class CppMacro : public CppElement
|
||||
{
|
||||
public:
|
||||
explicit CppMacro(const CPlusPlus::Macro ¯o);
|
||||
};
|
||||
|
||||
class CppDeclarableElement : public CppElement
|
||||
{
|
||||
public:
|
||||
explicit CppDeclarableElement(CPlusPlus::Symbol *declaration);
|
||||
|
||||
public:
|
||||
CPlusPlus::Symbol *declaration;
|
||||
QString name;
|
||||
QString qualifiedName;
|
||||
QString type;
|
||||
QIcon icon;
|
||||
};
|
||||
|
||||
class CppNamespace : public CppDeclarableElement
|
||||
{
|
||||
public:
|
||||
explicit CppNamespace(CPlusPlus::Symbol *declaration);
|
||||
};
|
||||
|
||||
class CppClass : public CppDeclarableElement
|
||||
{
|
||||
public:
|
||||
CppClass();
|
||||
explicit CppClass(CPlusPlus::Symbol *declaration);
|
||||
|
||||
bool operator==(const CppClass &other);
|
||||
|
||||
void lookupBases(CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context);
|
||||
void lookupDerived(CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot);
|
||||
|
||||
public:
|
||||
QList<CppClass> bases;
|
||||
QList<CppClass> derived;
|
||||
};
|
||||
|
||||
class CppFunction : public CppDeclarableElement
|
||||
{
|
||||
public:
|
||||
explicit CppFunction(CPlusPlus::Symbol *declaration);
|
||||
};
|
||||
|
||||
class CppEnum : public CppDeclarableElement
|
||||
{
|
||||
public:
|
||||
explicit CppEnum(CPlusPlus::Enum *declaration);
|
||||
};
|
||||
|
||||
class CppTypedef : public CppDeclarableElement
|
||||
{
|
||||
public:
|
||||
explicit CppTypedef(CPlusPlus::Symbol *declaration);
|
||||
};
|
||||
|
||||
class CppVariable : public CppDeclarableElement
|
||||
{
|
||||
public:
|
||||
CppVariable(CPlusPlus::Symbol *declaration,
|
||||
const CPlusPlus::LookupContext &context,
|
||||
CPlusPlus::Scope *scope);
|
||||
};
|
||||
|
||||
class CppEnumerator : public CppDeclarableElement
|
||||
{
|
||||
public:
|
||||
explicit CppEnumerator(CPlusPlus::EnumeratorDeclaration *declaration);
|
||||
};
|
||||
|
||||
} // namespace CppTools
|
||||
187
src/plugins/cpptools/cpphoverhandler.cpp
Normal file
187
src/plugins/cpptools/cpphoverhandler.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "cpphoverhandler.h"
|
||||
|
||||
#include "cppelementevaluator.h"
|
||||
|
||||
#include <coreplugin/helpmanager.h>
|
||||
#include <cpptools/baseeditordocumentprocessor.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/editordocumenthandle.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
#include <utils/textutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
|
||||
#include <QTextCursor>
|
||||
#include <QUrl>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
using namespace Core;
|
||||
using namespace TextEditor;
|
||||
|
||||
namespace {
|
||||
|
||||
CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(TextEditorWidget *editorWidget)
|
||||
{
|
||||
const QString filePath = editorWidget->textDocument()->filePath().toString();
|
||||
auto cppModelManager = CppTools::CppModelManager::instance();
|
||||
CppTools::CppEditorDocumentHandle *editorHandle = cppModelManager->cppEditorDocument(filePath);
|
||||
|
||||
if (editorHandle)
|
||||
return editorHandle->processor();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool editorDocumentProcessorHasDiagnosticAt(TextEditorWidget *editorWidget, int pos)
|
||||
{
|
||||
if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) {
|
||||
int line, column;
|
||||
if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column))
|
||||
return processor->hasDiagnosticsAt(line, column);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void processWithEditorDocumentProcessor(TextEditorWidget *editorWidget,
|
||||
const QPoint &point,
|
||||
int position,
|
||||
const QString &helpId)
|
||||
{
|
||||
if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) {
|
||||
int line, column;
|
||||
if (Utils::Text::convertPosition(editorWidget->document(), position, &line, &column)) {
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(2);
|
||||
processor->addDiagnosticToolTipToLayout(line, column, layout);
|
||||
Utils::ToolTip::show(point, layout, editorWidget, helpId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
||||
{
|
||||
m_positionForEditorDocumentProcessor = -1;
|
||||
|
||||
if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) {
|
||||
setPriority(Priority_Diagnostic);
|
||||
m_positionForEditorDocumentProcessor = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
QTextCursor tc(editorWidget->document());
|
||||
tc.setPosition(pos);
|
||||
|
||||
CppElementEvaluator evaluator(editorWidget);
|
||||
evaluator.setTextCursor(tc);
|
||||
evaluator.execute();
|
||||
if (evaluator.hasDiagnosis()) {
|
||||
setToolTip(evaluator.diagnosis());
|
||||
setPriority(Priority_Diagnostic);
|
||||
} else if (evaluator.identifiedCppElement()) {
|
||||
const QSharedPointer<CppElement> &cppElement = evaluator.cppElement();
|
||||
if (priority() != Priority_Diagnostic) {
|
||||
setToolTip(cppElement->tooltip);
|
||||
setPriority(cppElement->tooltip.isEmpty() ? Priority_None : Priority_Tooltip);
|
||||
}
|
||||
QStringList candidates = cppElement->helpIdCandidates;
|
||||
candidates.removeDuplicates();
|
||||
foreach (const QString &helpId, candidates) {
|
||||
if (helpId.isEmpty())
|
||||
continue;
|
||||
|
||||
const QMap<QString, QUrl> helpLinks = HelpManager::linksForIdentifier(helpId);
|
||||
if (!helpLinks.isEmpty()) {
|
||||
setLastHelpItemIdentified(HelpItem(helpId,
|
||||
cppElement->helpMark,
|
||||
cppElement->helpCategory,
|
||||
helpLinks));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppHoverHandler::decorateToolTip()
|
||||
{
|
||||
if (m_positionForEditorDocumentProcessor != -1)
|
||||
return;
|
||||
|
||||
if (Qt::mightBeRichText(toolTip()))
|
||||
setToolTip(toolTip().toHtmlEscaped());
|
||||
|
||||
if (priority() != Priority_Diagnostic)
|
||||
return;
|
||||
|
||||
const HelpItem &help = lastHelpItemIdentified();
|
||||
if (help.isValid()) {
|
||||
// If Qt is built with a namespace, we still show the tip without it, as
|
||||
// it is in the docs and for consistency with the doc extraction mechanism.
|
||||
const HelpItem::Category category = help.category();
|
||||
const QString &contents = help.extractContent(false);
|
||||
if (!contents.isEmpty()) {
|
||||
if (category == HelpItem::ClassOrNamespace)
|
||||
setToolTip(help.helpId() + contents);
|
||||
else
|
||||
setToolTip(contents);
|
||||
} else if (category == HelpItem::Typedef ||
|
||||
category == HelpItem::Enum ||
|
||||
category == HelpItem::ClassOrNamespace) {
|
||||
// This approach is a bit limited since it cannot be used for functions
|
||||
// because the help id doesn't really help in that case.
|
||||
QString prefix;
|
||||
if (category == HelpItem::Typedef)
|
||||
prefix = QLatin1String("typedef ");
|
||||
else if (category == HelpItem::Enum)
|
||||
prefix = QLatin1String("enum ");
|
||||
setToolTip(prefix + help.helpId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget,
|
||||
const QPoint &point)
|
||||
{
|
||||
if (m_positionForEditorDocumentProcessor == -1) {
|
||||
BaseHoverHandler::operateTooltip(editorWidget, point);
|
||||
return;
|
||||
}
|
||||
|
||||
const HelpItem helpItem = lastHelpItemIdentified();
|
||||
const QString helpId = helpItem.isValid() ? helpItem.helpId() : QString();
|
||||
processWithEditorDocumentProcessor(editorWidget, point, m_positionForEditorDocumentProcessor,
|
||||
helpId);
|
||||
}
|
||||
|
||||
} // namespace CppTools
|
||||
45
src/plugins/cpptools/cpphoverhandler.h
Normal file
45
src/plugins/cpptools/cpphoverhandler.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpptools_global.h"
|
||||
|
||||
#include <texteditor/basehoverhandler.h>
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
class CPPTOOLS_EXPORT CppHoverHandler : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
private:
|
||||
void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override;
|
||||
void decorateToolTip() override;
|
||||
void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override;
|
||||
|
||||
private:
|
||||
int m_positionForEditorDocumentProcessor = -1;
|
||||
};
|
||||
|
||||
} // namespace CppTools
|
||||
@@ -1293,8 +1293,13 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const
|
||||
return d->m_activeModelManagerSupport->completionAssistProvider();
|
||||
}
|
||||
|
||||
TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const
|
||||
{
|
||||
return d->m_activeModelManagerSupport->createHoverHandler();
|
||||
}
|
||||
|
||||
BaseEditorDocumentProcessor *CppModelManager::createEditorDocumentProcessor(
|
||||
TextEditor::TextDocument *baseTextDocument) const
|
||||
TextEditor::TextDocument *baseTextDocument) const
|
||||
{
|
||||
return d->m_activeModelManagerSupport->createEditorDocumentProcessor(baseTextDocument);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,10 @@ class IEditor;
|
||||
}
|
||||
namespace CPlusPlus { class LookupContext; }
|
||||
namespace ProjectExplorer { class Project; }
|
||||
namespace TextEditor { class TextDocument; }
|
||||
namespace TextEditor {
|
||||
class BaseHoverHandler;
|
||||
class TextDocument;
|
||||
} // namespace TextEditor
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
@@ -173,7 +176,8 @@ public:
|
||||
void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider);
|
||||
CppCompletionAssistProvider *completionAssistProvider() const;
|
||||
BaseEditorDocumentProcessor *createEditorDocumentProcessor(
|
||||
TextEditor::TextDocument *baseTextDocument) const;
|
||||
TextEditor::TextDocument *baseTextDocument) const;
|
||||
TextEditor::BaseHoverHandler *createHoverHandler() const;
|
||||
FollowSymbolInterface &followSymbolInterface() const;
|
||||
|
||||
void setIndexingSupport(CppIndexingSupport *indexingSupport);
|
||||
|
||||
@@ -30,7 +30,10 @@
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
namespace TextEditor { class TextDocument; }
|
||||
namespace TextEditor {
|
||||
class TextDocument;
|
||||
class BaseHoverHandler;
|
||||
} // namespace TextEditor
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
@@ -48,6 +51,7 @@ public:
|
||||
virtual ~ModelManagerSupport() = 0;
|
||||
|
||||
virtual CppCompletionAssistProvider *completionAssistProvider() = 0;
|
||||
virtual TextEditor::BaseHoverHandler *createHoverHandler() = 0;
|
||||
virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor(
|
||||
TextEditor::TextDocument *baseTextDocument) = 0;
|
||||
virtual FollowSymbolInterface &followSymbolInterface() = 0;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "cppcompletionassist.h"
|
||||
#include "cppmodelmanagersupportinternal.h"
|
||||
#include "cppfollowsymbolundercursor.h"
|
||||
#include "cpphoverhandler.h"
|
||||
#include "cpprefactoringengine.h"
|
||||
#include "builtineditordocumentprocessor.h"
|
||||
|
||||
@@ -74,6 +75,11 @@ CppCompletionAssistProvider *ModelManagerSupportInternal::completionAssistProvid
|
||||
return m_completionAssistProvider.data();
|
||||
}
|
||||
|
||||
TextEditor::BaseHoverHandler *ModelManagerSupportInternal::createHoverHandler()
|
||||
{
|
||||
return new CppHoverHandler;
|
||||
}
|
||||
|
||||
FollowSymbolInterface &ModelManagerSupportInternal::followSymbolInterface()
|
||||
{
|
||||
return *m_followSymbol;
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
virtual ~ModelManagerSupportInternal();
|
||||
|
||||
CppCompletionAssistProvider *completionAssistProvider() final;
|
||||
TextEditor::BaseHoverHandler *createHoverHandler() final;
|
||||
BaseEditorDocumentProcessor *createEditorDocumentProcessor(
|
||||
TextEditor::TextDocument *baseTextDocument) final;
|
||||
FollowSymbolInterface &followSymbolInterface() final;
|
||||
|
||||
@@ -32,11 +32,13 @@ HEADERS += \
|
||||
cppdoxygen.h \
|
||||
cppeditoroutline.h \
|
||||
cppeditorwidgetinterface.h \
|
||||
cppelementevaluator.h \
|
||||
cppfileiterationorder.h \
|
||||
cppfilesettingspage.h \
|
||||
cppfindreferences.h \
|
||||
cppfollowsymbolundercursor.h \
|
||||
cppfunctionsfilter.h \
|
||||
cpphoverhandler.h \
|
||||
cppincludesfilter.h \
|
||||
cppindexingsupport.h \
|
||||
cpplocalsymbols.h \
|
||||
@@ -125,11 +127,13 @@ SOURCES += \
|
||||
cppcurrentdocumentfilter.cpp \
|
||||
cppeditoroutline.cpp \
|
||||
cppdoxygen.cpp \
|
||||
cppelementevaluator.cpp \
|
||||
cppfileiterationorder.cpp \
|
||||
cppfilesettingspage.cpp \
|
||||
cppfindreferences.cpp \
|
||||
cppfollowsymbolundercursor.cpp \
|
||||
cppfunctionsfilter.cpp \
|
||||
cpphoverhandler.cpp \
|
||||
cppincludesfilter.cpp \
|
||||
cppindexingsupport.cpp \
|
||||
cpplocalsymbols.cpp \
|
||||
|
||||
@@ -90,6 +90,8 @@ Project {
|
||||
"cppeditoroutline.cpp",
|
||||
"cppeditoroutline.h",
|
||||
"cppeditorwidgetinterface.h",
|
||||
"cppelementevaluator.cpp",
|
||||
"cppelementevaluator.h",
|
||||
"cppfileiterationorder.cpp",
|
||||
"cppfileiterationorder.h",
|
||||
"cppfilesettingspage.cpp",
|
||||
@@ -101,6 +103,8 @@ Project {
|
||||
"cppfollowsymbolundercursor.h",
|
||||
"cppfunctionsfilter.cpp",
|
||||
"cppfunctionsfilter.h",
|
||||
"cpphoverhandler.cpp",
|
||||
"cpphoverhandler.h",
|
||||
"cppincludesfilter.cpp",
|
||||
"cppincludesfilter.h",
|
||||
"cppindexingsupport.cpp",
|
||||
|
||||
Reference in New Issue
Block a user