forked from qt-creator/qt-creator
Clang: Provide tooltips
This includes also the query data for the help system (F1) for an identifier under cursor. Regressions (libclang changes necessary): - Function signatures do not contain default values. - Aliases are not resolved for/at: - template types - qualified name of a type Fixes/Improvements: - Resolve "auto" - On a template type, show also the template parameter. - For a typedef like typedef long long superlong; the tooltip was "long long superlong", which was confusing. Now, "long long" is shown. New: - Show first or \brief paragraph of a documentation comment. - Show size of a class at definition. - Show size of a field member in class definition. Task-number: QTCREATORBUG-11259 Change-Id: Ie1a07930d0e882015d07dc43e35bb81a685cdeb8 Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -53,6 +53,9 @@ void ClangCodeModelClientInterface::dispatch(const MessageEnvelop &messageEnvelo
|
||||
case MessageType::FollowSymbolMessage:
|
||||
followSymbol(messageEnvelop.message<FollowSymbolMessage>());
|
||||
break;
|
||||
case MessageType::ToolTipMessage:
|
||||
tooltip(messageEnvelop.message<ToolTipMessage>());
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unknown ClangCodeModelClientMessage";
|
||||
}
|
||||
|
@@ -43,6 +43,8 @@ class RegisterUnsavedFilesForEditorMessage;
|
||||
class RequestDocumentAnnotationsMessage;
|
||||
class RequestReferencesMessage;
|
||||
class RequestFollowSymbolMessage;
|
||||
class RequestToolTipMessage;
|
||||
class ToolTipMessage;
|
||||
class UnregisterProjectPartsForEditorMessage;
|
||||
class UnregisterTranslationUnitsForEditorMessage;
|
||||
class UnregisterUnsavedFilesForEditorMessage;
|
||||
@@ -60,6 +62,7 @@ public:
|
||||
virtual void documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message) = 0;
|
||||
virtual void references(const ReferencesMessage &message) = 0;
|
||||
virtual void followSymbol(const FollowSymbolMessage &message) = 0;
|
||||
virtual void tooltip(const ToolTipMessage &message) = 0;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
@@ -31,3 +31,4 @@
|
||||
#include "documentannotationschangedmessage.h"
|
||||
#include "referencesmessage.h"
|
||||
#include "followsymbolmessage.h"
|
||||
#include "tooltipmessage.h"
|
||||
|
@@ -95,6 +95,11 @@ void ClangCodeModelClientProxy::followSymbol(const FollowSymbolMessage &message)
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelClientProxy::tooltip(const ToolTipMessage &message)
|
||||
{
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelClientProxy::readMessages()
|
||||
{
|
||||
for (const MessageEnvelop &message : m_readMessageBlock.readAll())
|
||||
|
@@ -57,6 +57,7 @@ public:
|
||||
void documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message) override;
|
||||
void references(const ReferencesMessage &message) override;
|
||||
void followSymbol(const FollowSymbolMessage &message) override;
|
||||
void tooltip(const ToolTipMessage &message) override;
|
||||
|
||||
void readMessages();
|
||||
|
||||
|
@@ -71,6 +71,9 @@ void ClangCodeModelServerInterface::dispatch(const MessageEnvelop &messageEnvelo
|
||||
case MessageType::RequestFollowSymbolMessage:
|
||||
requestFollowSymbol(messageEnvelop.message<RequestFollowSymbolMessage>());
|
||||
break;
|
||||
case MessageType::RequestToolTipMessage:
|
||||
requestToolTip(messageEnvelop.message<RequestToolTipMessage>());
|
||||
break;
|
||||
case MessageType::UpdateVisibleTranslationUnitsMessage:
|
||||
updateVisibleTranslationUnits(messageEnvelop.message<UpdateVisibleTranslationUnitsMessage>());
|
||||
break;
|
||||
|
@@ -50,6 +50,7 @@ public:
|
||||
virtual void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) = 0;
|
||||
virtual void requestReferences(const RequestReferencesMessage &message) = 0;
|
||||
virtual void requestFollowSymbol(const RequestFollowSymbolMessage &message) = 0;
|
||||
virtual void requestToolTip(const RequestToolTipMessage &message) = 0;
|
||||
virtual void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) = 0;
|
||||
};
|
||||
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "requestdocumentannotations.h"
|
||||
#include "requestreferencesmessage.h"
|
||||
#include "requestfollowsymbolmessage.h"
|
||||
#include "requesttooltipmessage.h"
|
||||
#include "unregisterunsavedfilesforeditormessage.h"
|
||||
#include "updatetranslationunitsforeditormessage.h"
|
||||
#include "updatevisibletranslationunitsmessage.h"
|
||||
|
@@ -96,6 +96,11 @@ void ClangCodeModelServerProxy::requestFollowSymbol(const RequestFollowSymbolMes
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServerProxy::requestToolTip(const RequestToolTipMessage &message)
|
||||
{
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServerProxy::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
m_writeMessageBlock.write(message);
|
||||
|
@@ -60,6 +60,7 @@ public:
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const RequestReferencesMessage &message) override;
|
||||
void requestFollowSymbol(const RequestFollowSymbolMessage &message) override;
|
||||
void requestToolTip(const RequestToolTipMessage &message) override;
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
};
|
||||
|
||||
|
@@ -68,6 +68,7 @@ SOURCES += \
|
||||
$$PWD/requestsourcelocationforrenamingmessage.cpp \
|
||||
$$PWD/requestsourcerangesanddiagnosticsforquerymessage.cpp \
|
||||
$$PWD/requestsourcerangesforquerymessage.cpp \
|
||||
$$PWD/requesttooltipmessage.cpp \
|
||||
$$PWD/sourcelocationcontainer.cpp \
|
||||
$$PWD/sourcelocationcontainerv2.cpp \
|
||||
$$PWD/sourcelocationscontainer.cpp \
|
||||
@@ -82,6 +83,8 @@ SOURCES += \
|
||||
$$PWD/sourcerangesforquerymessage.cpp \
|
||||
$$PWD/sourcerangewithtextcontainer.cpp \
|
||||
$$PWD/tokeninfocontainer.cpp \
|
||||
$$PWD/tooltipmessage.cpp \
|
||||
$$PWD/tooltipinfo.cpp \
|
||||
$$PWD/unregisterunsavedfilesforeditormessage.cpp \
|
||||
$$PWD/updatepchprojectpartsmessage.cpp \
|
||||
$$PWD/updatetranslationunitsforeditormessage.cpp \
|
||||
@@ -159,6 +162,7 @@ HEADERS += \
|
||||
$$PWD/requestsourcelocationforrenamingmessage.h \
|
||||
$$PWD/requestsourcerangesanddiagnosticsforquerymessage.h \
|
||||
$$PWD/requestsourcerangesforquerymessage.h \
|
||||
$$PWD/requesttooltipmessage.h \
|
||||
$$PWD/sourcelocationcontainer.h \
|
||||
$$PWD/sourcelocationcontainerv2.h \
|
||||
$$PWD/sourcelocationscontainer.h \
|
||||
@@ -176,6 +180,8 @@ HEADERS += \
|
||||
$$PWD/sourcerangewithtextcontainer.h \
|
||||
$$PWD/stringcache.h \
|
||||
$$PWD/tokeninfocontainer.h \
|
||||
$$PWD/tooltipmessage.h \
|
||||
$$PWD/tooltipinfo.h \
|
||||
$$PWD/unregisterunsavedfilesforeditormessage.h \
|
||||
$$PWD/updatepchprojectpartsmessage.h \
|
||||
$$PWD/updatetranslationunitsforeditormessage.h \
|
||||
|
@@ -120,6 +120,9 @@ enum class MessageType : quint8 {
|
||||
RequestFollowSymbolMessage,
|
||||
FollowSymbolMessage,
|
||||
|
||||
RequestToolTipMessage,
|
||||
ToolTipMessage,
|
||||
|
||||
UpdateVisibleTranslationUnitsMessage,
|
||||
|
||||
CompleteCodeMessage,
|
||||
|
@@ -37,7 +37,8 @@ QDebug operator<<(QDebug debug, const FileContainer &container)
|
||||
<< container.filePath() << ", "
|
||||
<< container.projectPartId() << ", "
|
||||
<< container.fileArguments() << ", "
|
||||
<< container.documentRevision();
|
||||
<< container.documentRevision() << ", "
|
||||
<< container.textCodecName();
|
||||
|
||||
if (container.hasUnsavedFileContent()) {
|
||||
const Utf8String fileWithContent = debugWriteFileForInspection(
|
||||
|
@@ -42,10 +42,12 @@ public:
|
||||
const Utf8String &projectPartId,
|
||||
const Utf8String &unsavedFileContent = Utf8String(),
|
||||
bool hasUnsavedFileContent = false,
|
||||
quint32 documentRevision = 0)
|
||||
quint32 documentRevision = 0,
|
||||
const Utf8String &textCodecName = Utf8String())
|
||||
: m_filePath(filePath),
|
||||
m_projectPartId(projectPartId),
|
||||
m_unsavedFileContent(unsavedFileContent),
|
||||
m_textCodecName(textCodecName),
|
||||
m_documentRevision(documentRevision),
|
||||
m_hasUnsavedFileContent(hasUnsavedFileContent)
|
||||
{
|
||||
@@ -98,6 +100,11 @@ public:
|
||||
return m_unsavedFileContent;
|
||||
}
|
||||
|
||||
const Utf8String &textCodecName() const
|
||||
{
|
||||
return m_textCodecName;
|
||||
}
|
||||
|
||||
bool hasUnsavedFileContent() const
|
||||
{
|
||||
return m_hasUnsavedFileContent;
|
||||
@@ -114,6 +121,7 @@ public:
|
||||
out << container.m_projectPartId;
|
||||
out << container.m_fileArguments;
|
||||
out << container.m_unsavedFileContent;
|
||||
out << container.m_textCodecName;
|
||||
out << container.m_documentRevision;
|
||||
out << container.m_hasUnsavedFileContent;
|
||||
|
||||
@@ -126,6 +134,7 @@ public:
|
||||
in >> container.m_projectPartId;
|
||||
in >> container.m_fileArguments;
|
||||
in >> container.m_unsavedFileContent;
|
||||
in >> container.m_textCodecName;
|
||||
in >> container.m_documentRevision;
|
||||
in >> container.m_hasUnsavedFileContent;
|
||||
|
||||
@@ -142,6 +151,7 @@ private:
|
||||
Utf8String m_projectPartId;
|
||||
Utf8StringVector m_fileArguments;
|
||||
Utf8String m_unsavedFileContent;
|
||||
Utf8String m_textCodecName;
|
||||
quint32 m_documentRevision = 0;
|
||||
bool m_hasUnsavedFileContent = false;
|
||||
};
|
||||
|
@@ -68,6 +68,9 @@ QDebug operator<<(QDebug debug, const MessageEnvelop &messageEnvelop)
|
||||
case MessageType::RequestReferencesMessage:
|
||||
qDebug() << messageEnvelop.message<RequestReferencesMessage>();
|
||||
break;
|
||||
case MessageType::RequestToolTipMessage:
|
||||
qDebug() << messageEnvelop.message<RequestToolTipMessage>();
|
||||
break;
|
||||
case MessageType::UpdateVisibleTranslationUnitsMessage:
|
||||
qDebug() << messageEnvelop.message<UpdateVisibleTranslationUnitsMessage>();
|
||||
break;
|
||||
@@ -83,6 +86,9 @@ QDebug operator<<(QDebug debug, const MessageEnvelop &messageEnvelop)
|
||||
case MessageType::ReferencesMessage:
|
||||
qDebug() << messageEnvelop.message<ReferencesMessage>();
|
||||
break;
|
||||
case MessageType::ToolTipMessage:
|
||||
qDebug() << messageEnvelop.message<ToolTipMessage>();
|
||||
break;
|
||||
case MessageType::DocumentAnnotationsChangedMessage:
|
||||
qDebug() << messageEnvelop.message<DocumentAnnotationsChangedMessage>();
|
||||
break;
|
||||
|
48
src/libs/clangsupport/requesttooltipmessage.cpp
Normal file
48
src/libs/clangsupport/requesttooltipmessage.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "requesttooltipmessage.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
quint64 RequestToolTipMessage::ticketCounter = 0;
|
||||
|
||||
QDebug operator<<(QDebug debug, const RequestToolTipMessage &message)
|
||||
{
|
||||
debug.nospace() << "RequestToolTipMessage(";
|
||||
|
||||
debug.nospace() << message.m_fileContainer << ", ";
|
||||
debug.nospace() << message.m_ticketNumber << ", ";
|
||||
debug.nospace() << message.m_line << ", ";
|
||||
debug.nospace() << message.m_column << ", ";
|
||||
|
||||
debug.nospace() << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
94
src/libs/clangsupport/requesttooltipmessage.h
Normal file
94
src/libs/clangsupport/requesttooltipmessage.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "clangsupport_global.h"
|
||||
|
||||
#include "filecontainer.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
// TODO: De-duplicate with RequestReferencesMessage?
|
||||
class RequestToolTipMessage
|
||||
{
|
||||
public:
|
||||
RequestToolTipMessage() = default;
|
||||
RequestToolTipMessage(const FileContainer &fileContainer, quint32 line, quint32 column)
|
||||
: m_fileContainer(fileContainer)
|
||||
, m_ticketNumber(++ticketCounter)
|
||||
, m_line(line)
|
||||
, m_column(column)
|
||||
{
|
||||
}
|
||||
|
||||
const FileContainer fileContainer() const { return m_fileContainer; }
|
||||
quint32 line() const { return m_line; }
|
||||
quint32 column() const { return m_column; }
|
||||
quint64 ticketNumber() const { return m_ticketNumber; }
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &out, const RequestToolTipMessage &message)
|
||||
{
|
||||
out << message.m_fileContainer;
|
||||
out << message.m_ticketNumber;
|
||||
out << message.m_line;
|
||||
out << message.m_column;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &in, RequestToolTipMessage &message)
|
||||
{
|
||||
in >> message.m_fileContainer;
|
||||
in >> message.m_ticketNumber;
|
||||
in >> message.m_line;
|
||||
in >> message.m_column;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
friend bool operator==(const RequestToolTipMessage &first,
|
||||
const RequestToolTipMessage &second)
|
||||
{
|
||||
return first.m_ticketNumber == second.m_ticketNumber
|
||||
&& first.m_line == second.m_line
|
||||
&& first.m_column == second.m_column
|
||||
&& first.m_fileContainer == second.m_fileContainer;
|
||||
}
|
||||
|
||||
friend CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const RequestToolTipMessage &message);
|
||||
|
||||
private:
|
||||
FileContainer m_fileContainer;
|
||||
quint64 m_ticketNumber = 0;
|
||||
quint32 m_line = 0;
|
||||
quint32 m_column = 0;
|
||||
static CLANGSUPPORT_EXPORT quint64 ticketCounter;
|
||||
};
|
||||
|
||||
DECLARE_MESSAGE(RequestToolTipMessage);
|
||||
} // namespace ClangBackEnd
|
65
src/libs/clangsupport/tooltipinfo.cpp
Normal file
65
src/libs/clangsupport/tooltipinfo.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "tooltipinfo.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
#define RETURN_TEXT_FOR_CASE(enumValue) case ToolTipInfo::enumValue: return #enumValue
|
||||
const char *qdocCategoryToString(ToolTipInfo::QdocCategory category)
|
||||
{
|
||||
switch (category) {
|
||||
RETURN_TEXT_FOR_CASE(Unknown);
|
||||
RETURN_TEXT_FOR_CASE(ClassOrNamespace);
|
||||
RETURN_TEXT_FOR_CASE(Enum);
|
||||
RETURN_TEXT_FOR_CASE(Typedef);
|
||||
RETURN_TEXT_FOR_CASE(Macro);
|
||||
RETURN_TEXT_FOR_CASE(Brief);
|
||||
RETURN_TEXT_FOR_CASE(Function);
|
||||
}
|
||||
|
||||
return "UnhandledQdocCategory";
|
||||
}
|
||||
#undef RETURN_TEXT_FOR_CASE
|
||||
|
||||
QDebug operator<<(QDebug debug, const ToolTipInfo &message)
|
||||
{
|
||||
debug.nospace() << "ToolTipInfo(";
|
||||
|
||||
debug.nospace() << message.m_text << ", ";
|
||||
debug.nospace() << message.m_briefComment << ", ";
|
||||
debug.nospace() << message.m_qdocIdCandidates << ", ";
|
||||
debug.nospace() << message.m_qdocMark << ", ";
|
||||
debug.nospace() << qdocCategoryToString(message.m_qdocCategory) << ", ";
|
||||
debug.nospace() << message.m_sizeInBytes << ", ";
|
||||
|
||||
debug.nospace() << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
124
src/libs/clangsupport/tooltipinfo.h
Normal file
124
src/libs/clangsupport/tooltipinfo.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 <utf8string.h>
|
||||
#include <utf8stringvector.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class ToolTipInfo
|
||||
{
|
||||
public:
|
||||
enum QdocCategory : quint8 {
|
||||
Unknown,
|
||||
ClassOrNamespace,
|
||||
Enum,
|
||||
Typedef,
|
||||
Macro,
|
||||
Brief,
|
||||
Function,
|
||||
};
|
||||
|
||||
public:
|
||||
ToolTipInfo() = default;
|
||||
ToolTipInfo(const Utf8String &text) : m_text(text) {}
|
||||
|
||||
const Utf8String &text() const { return m_text; }
|
||||
void setText(const Utf8String &text) { m_text = text; }
|
||||
|
||||
const Utf8String &briefComment() const { return m_briefComment; }
|
||||
void setBriefComment(const Utf8String &briefComment) { m_briefComment = briefComment; }
|
||||
|
||||
const Utf8StringVector &qdocIdCandidates() const { return m_qdocIdCandidates; }
|
||||
void setQdocIdCandidates(const Utf8StringVector &qdocIdCandidates)
|
||||
{ m_qdocIdCandidates = qdocIdCandidates; }
|
||||
|
||||
const Utf8String &qdocMark() const { return m_qdocMark; }
|
||||
void setQdocMark(const Utf8String &qdocMark) { m_qdocMark = qdocMark; }
|
||||
|
||||
const QdocCategory &qdocCategory() const { return m_qdocCategory; }
|
||||
void setQdocCategory(const QdocCategory &qdocCategory) { m_qdocCategory = qdocCategory; }
|
||||
|
||||
const Utf8String &sizeInBytes() const { return m_sizeInBytes; }
|
||||
void setSizeInBytes(const Utf8String &sizeInBytes) { m_sizeInBytes = sizeInBytes; }
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &out, const ToolTipInfo &message)
|
||||
{
|
||||
out << message.m_text;
|
||||
out << message.m_briefComment;
|
||||
out << message.m_qdocIdCandidates;
|
||||
out << message.m_qdocMark;
|
||||
out << static_cast<quint8>(message.m_qdocCategory);
|
||||
out << message.m_sizeInBytes;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &in, ToolTipInfo &message)
|
||||
{
|
||||
quint8 qdocCategory;
|
||||
|
||||
in >> message.m_text;
|
||||
in >> message.m_briefComment;
|
||||
in >> message.m_qdocIdCandidates;
|
||||
in >> message.m_qdocMark;
|
||||
in >> qdocCategory;
|
||||
in >> message.m_sizeInBytes;
|
||||
|
||||
message.m_qdocCategory = static_cast<QdocCategory>(qdocCategory);
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
friend bool operator==(const ToolTipInfo &first, const ToolTipInfo &second)
|
||||
{
|
||||
return first.m_text == second.m_text
|
||||
&& first.m_briefComment == second.m_briefComment
|
||||
&& first.m_qdocIdCandidates == second.m_qdocIdCandidates
|
||||
&& first.m_qdocMark == second.m_qdocMark
|
||||
&& first.m_qdocCategory == second.m_qdocCategory
|
||||
&& first.m_sizeInBytes == second.m_sizeInBytes;
|
||||
}
|
||||
|
||||
friend QDebug operator<<(QDebug debug, const ToolTipInfo &message);
|
||||
friend std::ostream &operator<<(std::ostream &os, const ToolTipInfo &message);
|
||||
|
||||
private:
|
||||
Utf8String m_text;
|
||||
Utf8String m_briefComment;
|
||||
|
||||
Utf8StringVector m_qdocIdCandidates;
|
||||
Utf8String m_qdocMark;
|
||||
QdocCategory m_qdocCategory = Unknown;
|
||||
|
||||
// For class definition and for class fields.
|
||||
Utf8String m_sizeInBytes;
|
||||
};
|
||||
|
||||
const char *qdocCategoryToString(ToolTipInfo::QdocCategory category);
|
||||
|
||||
} // namespace ClangBackEnd
|
44
src/libs/clangsupport/tooltipmessage.cpp
Normal file
44
src/libs/clangsupport/tooltipmessage.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "tooltipmessage.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
QDebug operator<<(QDebug debug, const ToolTipMessage &message)
|
||||
{
|
||||
debug.nospace() << "ToolTipMessage("
|
||||
<< message.fileContainer()
|
||||
<< ", " << message.m_ticketNumber
|
||||
<< ", " << message.m_toolTipInfo;
|
||||
|
||||
debug.nospace() << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
87
src/libs/clangsupport/tooltipmessage.h
Normal file
87
src/libs/clangsupport/tooltipmessage.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "filecontainer.h"
|
||||
#include "tooltipinfo.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class ToolTipMessage
|
||||
{
|
||||
public:
|
||||
ToolTipMessage() = default;
|
||||
ToolTipMessage(const FileContainer &fileContainer,
|
||||
const ToolTipInfo &toolTipInfo,
|
||||
quint64 ticketNumber)
|
||||
: m_fileContainer(fileContainer)
|
||||
, m_toolTipInfo(toolTipInfo)
|
||||
, m_ticketNumber(ticketNumber)
|
||||
{
|
||||
}
|
||||
|
||||
const FileContainer &fileContainer() const { return m_fileContainer; }
|
||||
const ToolTipInfo &toolTipInfo() const { return m_toolTipInfo; }
|
||||
quint64 ticketNumber() const { return m_ticketNumber; }
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &out, const ToolTipMessage &message)
|
||||
{
|
||||
out << message.m_fileContainer;
|
||||
out << message.m_toolTipInfo;;
|
||||
out << message.m_ticketNumber;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &in, ToolTipMessage &message)
|
||||
{
|
||||
in >> message.m_fileContainer;
|
||||
in >> message.m_toolTipInfo;
|
||||
in >> message.m_ticketNumber;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
friend bool operator==(const ToolTipMessage &first, const ToolTipMessage &second)
|
||||
{
|
||||
return first.m_ticketNumber == second.m_ticketNumber
|
||||
&& first.m_fileContainer == second.m_fileContainer
|
||||
&& first.m_toolTipInfo == second.m_toolTipInfo;
|
||||
}
|
||||
|
||||
friend CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const ToolTipMessage &message);
|
||||
friend std::ostream &operator<<(std::ostream &os, const ToolTipMessage &message);
|
||||
|
||||
private:
|
||||
FileContainer m_fileContainer;
|
||||
ToolTipInfo m_toolTipInfo;
|
||||
quint64 m_ticketNumber = 0;
|
||||
};
|
||||
|
||||
DECLARE_MESSAGE(ToolTipMessage)
|
||||
} // namespace ClangBackEnd
|
@@ -171,7 +171,8 @@ public:
|
||||
byteArray.reserve(reserveSize);
|
||||
}
|
||||
|
||||
static Utf8String number(int number, int base=10)
|
||||
template<typename T>
|
||||
static Utf8String number(T number, int base = 10)
|
||||
{
|
||||
return Utf8String::fromByteArray(QByteArray::number(number, base));
|
||||
}
|
||||
|
@@ -392,6 +392,15 @@ QFuture<CppTools::CursorInfo> BackendCommunicator::requestLocalReferences(
|
||||
return m_receiver.addExpectedReferencesMessage(message.ticketNumber(), textDocument);
|
||||
}
|
||||
|
||||
QFuture<CppTools::ToolTipInfo> BackendCommunicator::requestToolTip(
|
||||
const FileContainer &fileContainer, quint32 line, quint32 column)
|
||||
{
|
||||
const RequestToolTipMessage message(fileContainer, line, column);
|
||||
m_sender->requestToolTip(message);
|
||||
|
||||
return m_receiver.addExpectedToolTipMessage(message.ticketNumber());
|
||||
}
|
||||
|
||||
QFuture<CppTools::SymbolInfo> BackendCommunicator::requestFollowSymbol(
|
||||
const FileContainer &curFileContainer,
|
||||
quint32 line,
|
||||
|
@@ -82,6 +82,9 @@ public:
|
||||
quint32 line,
|
||||
quint32 column,
|
||||
QTextDocument *textDocument);
|
||||
QFuture<CppTools::ToolTipInfo> requestToolTip(const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column);
|
||||
QFuture<CppTools::SymbolInfo> requestFollowSymbol(const FileContainer &curFileContainer,
|
||||
quint32 line,
|
||||
quint32 column);
|
||||
|
@@ -128,6 +128,18 @@ QFuture<CppTools::SymbolInfo> BackendReceiver::addExpectedRequestFollowSymbolMes
|
||||
return futureInterface.future();
|
||||
}
|
||||
|
||||
QFuture<CppTools::ToolTipInfo> BackendReceiver::addExpectedToolTipMessage(quint64 ticket)
|
||||
{
|
||||
QTC_CHECK(!m_toolTipsTable.contains(ticket));
|
||||
|
||||
QFutureInterface<CppTools::ToolTipInfo> futureInterface;
|
||||
futureInterface.reportStarted();
|
||||
|
||||
m_toolTipsTable.insert(ticket, futureInterface);
|
||||
|
||||
return futureInterface.future();
|
||||
}
|
||||
|
||||
bool BackendReceiver::isExpectingCodeCompletedMessage() const
|
||||
{
|
||||
return !m_assistProcessorsTable.isEmpty();
|
||||
@@ -272,6 +284,72 @@ void BackendReceiver::references(const ReferencesMessage &message)
|
||||
futureInterface.reportFinished();
|
||||
}
|
||||
|
||||
static TextEditor::HelpItem::Category toHelpItemCategory(ToolTipInfo::QdocCategory category)
|
||||
{
|
||||
switch (category) {
|
||||
case ToolTipInfo::Unknown:
|
||||
return TextEditor::HelpItem::Unknown;
|
||||
case ToolTipInfo::ClassOrNamespace:
|
||||
return TextEditor::HelpItem::ClassOrNamespace;
|
||||
case ToolTipInfo::Enum:
|
||||
return TextEditor::HelpItem::Enum;
|
||||
case ToolTipInfo::Typedef:
|
||||
return TextEditor::HelpItem::Typedef;
|
||||
case ToolTipInfo::Macro:
|
||||
return TextEditor::HelpItem::Macro;
|
||||
case ToolTipInfo::Brief:
|
||||
return TextEditor::HelpItem::Brief;
|
||||
case ToolTipInfo::Function:
|
||||
return TextEditor::HelpItem::Function;
|
||||
}
|
||||
|
||||
return TextEditor::HelpItem::Unknown;
|
||||
}
|
||||
|
||||
static QStringList toStringList(const Utf8StringVector &utf8StringVector)
|
||||
{
|
||||
QStringList list;
|
||||
list.reserve(utf8StringVector.size());
|
||||
|
||||
for (const Utf8String &utf8String : utf8StringVector)
|
||||
list << utf8String.toString();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static CppTools::ToolTipInfo toToolTipInfo(const ToolTipMessage &message)
|
||||
{
|
||||
CppTools::ToolTipInfo info;
|
||||
|
||||
const ToolTipInfo backendInfo = message.toolTipInfo();
|
||||
|
||||
info.text = backendInfo.text();
|
||||
info.briefComment = backendInfo.briefComment();
|
||||
|
||||
info.qDocIdCandidates = toStringList(backendInfo.qdocIdCandidates());
|
||||
info.qDocMark = backendInfo.qdocMark();
|
||||
info.qDocCategory = toHelpItemCategory(backendInfo.qdocCategory());
|
||||
|
||||
info.sizeInBytes = backendInfo.sizeInBytes();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void BackendReceiver::tooltip(const ToolTipMessage &message)
|
||||
{
|
||||
qCDebugIpc() << "ToolTipMessage" << message.toolTipInfo().text();
|
||||
|
||||
const quint64 ticket = message.ticketNumber();
|
||||
QFutureInterface<CppTools::ToolTipInfo> futureInterface = m_toolTipsTable.take(ticket);
|
||||
QTC_CHECK(futureInterface != QFutureInterface<CppTools::ToolTipInfo>());
|
||||
|
||||
if (futureInterface.isCanceled())
|
||||
return; // A new request was issued making this one outdated.
|
||||
|
||||
futureInterface.reportResult(toToolTipInfo(message));
|
||||
futureInterface.reportFinished();
|
||||
}
|
||||
|
||||
void BackendReceiver::followSymbol(const ClangBackEnd::FollowSymbolMessage &message)
|
||||
{
|
||||
qCDebugIpc() << "FollowSymbolMessage with"
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <cpptools/cppcursorinfo.h>
|
||||
#include <cpptools/cppsymbolinfo.h>
|
||||
#include <cpptools/baseeditordocumentprocessor.h>
|
||||
|
||||
#include <clangsupport/clangcodemodelclientinterface.h>
|
||||
|
||||
@@ -59,6 +60,7 @@ public:
|
||||
const CppTools::SemanticInfo::LocalUseMap &localUses
|
||||
= CppTools::SemanticInfo::LocalUseMap());
|
||||
QFuture<CppTools::SymbolInfo> addExpectedRequestFollowSymbolMessage(quint64 ticket);
|
||||
QFuture<CppTools::ToolTipInfo> addExpectedToolTipMessage(quint64 ticket);
|
||||
bool isExpectingCodeCompletedMessage() const;
|
||||
|
||||
void reset();
|
||||
@@ -70,6 +72,7 @@ private:
|
||||
|
||||
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &message) override;
|
||||
void references(const ClangBackEnd::ReferencesMessage &message) override;
|
||||
void tooltip(const ClangBackEnd::ToolTipMessage &message) override;
|
||||
void followSymbol(const ClangBackEnd::FollowSymbolMessage &message) override;
|
||||
|
||||
private:
|
||||
@@ -89,7 +92,7 @@ private:
|
||||
CppTools::SemanticInfo::LocalUseMap localUses;
|
||||
};
|
||||
QHash<quint64, ReferencesEntry> m_referencesTable;
|
||||
|
||||
QHash<quint64, QFutureInterface<CppTools::ToolTipInfo>> m_toolTipsTable;
|
||||
QHash<quint64, QFutureInterface<CppTools::SymbolInfo>> m_followTable;
|
||||
};
|
||||
|
||||
|
@@ -120,6 +120,13 @@ void BackendSender::requestReferences(const RequestReferencesMessage &message)
|
||||
m_connection->serverProxy().requestReferences(message);
|
||||
}
|
||||
|
||||
void BackendSender::requestToolTip(const RequestToolTipMessage &message)
|
||||
{
|
||||
QTC_CHECK(m_connection->isConnected());
|
||||
qCDebug(ipcLog) << ">>>" << message;
|
||||
m_connection->serverProxy().requestToolTip(message);
|
||||
}
|
||||
|
||||
void BackendSender::requestFollowSymbol(const RequestFollowSymbolMessage &message)
|
||||
{
|
||||
QTC_CHECK(m_connection->isConnected());
|
||||
|
@@ -48,6 +48,7 @@ public:
|
||||
void completeCode(const ClangBackEnd::CompleteCodeMessage &message) override;
|
||||
void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const ClangBackEnd::RequestReferencesMessage &message) override;
|
||||
void requestToolTip(const ClangBackEnd::RequestToolTipMessage &message) override;
|
||||
void requestFollowSymbol(const ClangBackEnd::RequestFollowSymbolMessage &message) override;
|
||||
void updateVisibleTranslationUnits(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
|
||||
|
@@ -30,6 +30,7 @@ SOURCES += \
|
||||
clangfixitoperationsextractor.cpp \
|
||||
clangfollowsymbol.cpp \
|
||||
clangfunctionhintmodel.cpp \
|
||||
clanghoverhandler.cpp \
|
||||
clangtokeninfosreporter.cpp \
|
||||
clangmodelmanagersupport.cpp \
|
||||
clangpreprocessorassistproposalitem.cpp \
|
||||
@@ -66,6 +67,7 @@ HEADERS += \
|
||||
clangfixitoperationsextractor.h \
|
||||
clangfollowsymbol.h \
|
||||
clangfunctionhintmodel.h \
|
||||
clanghoverhandler.h \
|
||||
clangisdiagnosticrelatedtolocation.h \
|
||||
clangmodelmanagersupport.h \
|
||||
clangpreprocessorassistproposalitem.h \
|
||||
|
@@ -80,6 +80,8 @@ QtcPlugin {
|
||||
"clangfollowsymbol.h",
|
||||
"clangfunctionhintmodel.cpp",
|
||||
"clangfunctionhintmodel.h",
|
||||
"clanghoverhandler.cpp",
|
||||
"clanghoverhandler.h",
|
||||
"clangtokeninfosreporter.cpp",
|
||||
"clangtokeninfosreporter.h",
|
||||
"clangisdiagnosticrelatedtolocation.h",
|
||||
|
@@ -375,6 +375,15 @@ ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column)
|
||||
static_cast<quint32>(column));
|
||||
}
|
||||
|
||||
QFuture<CppTools::ToolTipInfo> ClangEditorDocumentProcessor::toolTipInfo(const QByteArray &codecName,
|
||||
int line,
|
||||
int column)
|
||||
{
|
||||
return m_communicator.requestToolTip(simpleFileContainer(codecName),
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column));
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const
|
||||
{
|
||||
return fileContainerWithArguments(m_projectPart.data());
|
||||
@@ -480,13 +489,19 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
|
||||
};
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::simpleFileContainer() const
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::simpleFileContainer(
|
||||
const QByteArray &codecName) const
|
||||
{
|
||||
Utf8String projectPartId;
|
||||
if (m_projectPart)
|
||||
projectPartId = m_projectPart->id();
|
||||
|
||||
return ClangBackEnd::FileContainer(filePath(), projectPartId, Utf8String(), false, revision());
|
||||
return ClangBackEnd::FileContainer(filePath(),
|
||||
projectPartId,
|
||||
Utf8String(),
|
||||
false,
|
||||
revision(),
|
||||
Utf8String::fromByteArray(codecName));
|
||||
}
|
||||
|
||||
static CppTools::ProjectPart projectPartForLanguageOption(CppTools::ProjectPart *projectPart)
|
||||
|
@@ -88,6 +88,9 @@ public:
|
||||
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams ¶ms) override;
|
||||
QFuture<CppTools::CursorInfo> requestLocalReferences(const QTextCursor &cursor) override;
|
||||
QFuture<CppTools::SymbolInfo> requestFollowSymbol(int line, int column) override;
|
||||
QFuture<CppTools::ToolTipInfo> toolTipInfo(const QByteArray &codecName,
|
||||
int line,
|
||||
int column) override;
|
||||
|
||||
ClangBackEnd::FileContainer fileContainerWithArguments() const;
|
||||
|
||||
@@ -106,7 +109,7 @@ private:
|
||||
void requestDocumentAnnotations(const QString &projectpartId);
|
||||
HeaderErrorDiagnosticWidgetCreator creatorForHeaderErrorDiagnosticWidget(
|
||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic);
|
||||
ClangBackEnd::FileContainer simpleFileContainer() const;
|
||||
ClangBackEnd::FileContainer simpleFileContainer(const QByteArray &codecName = QByteArray()) const;
|
||||
ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const;
|
||||
ClangBackEnd::FileContainer fileContainerWithArgumentsAndDocumentContent(
|
||||
CppTools::ProjectPart *projectPart) const;
|
||||
|
232
src/plugins/clangcodemodel/clanghoverhandler.cpp
Normal file
232
src/plugins/clangcodemodel/clanghoverhandler.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "clanghoverhandler.h"
|
||||
|
||||
#include <coreplugin/helpmanager.h>
|
||||
#include <cpptools/baseeditordocumentprocessor.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/editordocumenthandle.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/textutils.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
|
||||
#include <QFutureWatcher>
|
||||
#include <QLoggingCategory>
|
||||
#include <QTextCodec>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
Q_LOGGING_CATEGORY(hoverLog, "qtc.clangcodemodel.hover");
|
||||
|
||||
using namespace TextEditor;
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QFuture<CppTools::ToolTipInfo> editorDocumentHandlesToolTipInfo(
|
||||
TextEditorWidget *editorWidget, int pos)
|
||||
{
|
||||
const QByteArray textCodecName = editorWidget->textDocument()->codec()->name();
|
||||
if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) {
|
||||
int line, column;
|
||||
if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column))
|
||||
return processor->toolTipInfo(textCodecName, line, column + 1);
|
||||
}
|
||||
|
||||
return QFuture<CppTools::ToolTipInfo>();
|
||||
}
|
||||
|
||||
ClangHoverHandler::ClangHoverHandler()
|
||||
{
|
||||
setIsAsyncHandler(true);
|
||||
}
|
||||
|
||||
ClangHoverHandler::~ClangHoverHandler()
|
||||
{
|
||||
cancelAsyncCheck();
|
||||
}
|
||||
|
||||
void ClangHoverHandler::identifyMatchAsync(TextEditorWidget *editorWidget,
|
||||
int pos,
|
||||
BaseHoverHandler::ReportPriority report)
|
||||
{
|
||||
// Reset
|
||||
m_futureWatcher.reset();
|
||||
m_cursorPosition = -1;
|
||||
|
||||
// Check for diagnostics (sync)
|
||||
if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) {
|
||||
qCDebug(hoverLog) << "Checking for diagnostic at" << pos;
|
||||
setPriority(Priority_Diagnostic);
|
||||
m_cursorPosition = pos;
|
||||
report(priority());
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for tooltips (async)
|
||||
QFuture<CppTools::ToolTipInfo> future = editorDocumentHandlesToolTipInfo(editorWidget, pos);
|
||||
if (QTC_GUARD(future.isRunning())) {
|
||||
qCDebug(hoverLog) << "Requesting tooltip info at" << pos;
|
||||
m_reportPriority = report;
|
||||
m_futureWatcher.reset(new QFutureWatcher<CppTools::ToolTipInfo>());
|
||||
QObject::connect(m_futureWatcher.data(), &QFutureWatcherBase::finished, [this]() {
|
||||
processToolTipInfo(m_futureWatcher->result());
|
||||
});
|
||||
m_futureWatcher->setFuture(future);
|
||||
return;
|
||||
}
|
||||
|
||||
report(Priority_None); // Ops, something went wrong.
|
||||
}
|
||||
|
||||
void ClangHoverHandler::cancelAsyncCheck()
|
||||
{
|
||||
if (m_futureWatcher)
|
||||
m_futureWatcher->cancel();
|
||||
}
|
||||
|
||||
#define RETURN_TEXT_FOR_CASE(enumValue) case TextEditor::HelpItem::enumValue: return #enumValue
|
||||
static const char *helpItemCategoryAsString(TextEditor::HelpItem::Category category)
|
||||
{
|
||||
switch (category) {
|
||||
RETURN_TEXT_FOR_CASE(Unknown);
|
||||
RETURN_TEXT_FOR_CASE(ClassOrNamespace);
|
||||
RETURN_TEXT_FOR_CASE(Enum);
|
||||
RETURN_TEXT_FOR_CASE(Typedef);
|
||||
RETURN_TEXT_FOR_CASE(Macro);
|
||||
RETURN_TEXT_FOR_CASE(Brief);
|
||||
RETURN_TEXT_FOR_CASE(Function);
|
||||
RETURN_TEXT_FOR_CASE(QmlComponent);
|
||||
RETURN_TEXT_FOR_CASE(QmlProperty);
|
||||
RETURN_TEXT_FOR_CASE(QMakeVariableOfFunction);
|
||||
}
|
||||
|
||||
return "UnhandledHelpItemCategory";
|
||||
}
|
||||
#undef RETURN_TEXT_FOR_CASE
|
||||
|
||||
void ClangHoverHandler::processToolTipInfo(const CppTools::ToolTipInfo &info)
|
||||
{
|
||||
qCDebug(hoverLog) << "Processing tooltip info" << info.text;
|
||||
|
||||
QString text = info.text;
|
||||
if (!info.briefComment.isEmpty())
|
||||
text.append("\n\n" + info.briefComment);
|
||||
|
||||
for (const QString &qdocIdCandidate : info.qDocIdCandidates) {
|
||||
qCDebug(hoverLog) << "Querying help manager with"
|
||||
<< qdocIdCandidate
|
||||
<< info.qDocMark
|
||||
<< helpItemCategoryAsString(info.qDocCategory);
|
||||
const QMap<QString, QUrl> helpLinks = Core::HelpManager::linksForIdentifier(qdocIdCandidate);
|
||||
if (!helpLinks.isEmpty()) {
|
||||
qCDebug(hoverLog) << " Match!";
|
||||
setLastHelpItemIdentified(
|
||||
HelpItem(qdocIdCandidate, info.qDocMark, info.qDocCategory, helpLinks));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!info.sizeInBytes.isEmpty())
|
||||
text.append(tr("\n\n%1 bytes").arg(info.sizeInBytes));
|
||||
|
||||
setToolTip(text);
|
||||
m_reportPriority(priority());
|
||||
}
|
||||
|
||||
void ClangHoverHandler::decorateToolTip()
|
||||
{
|
||||
if (priority() == Priority_Diagnostic)
|
||||
return;
|
||||
|
||||
if (Qt::mightBeRichText(toolTip()))
|
||||
setToolTip(toolTip().toHtmlEscaped());
|
||||
|
||||
const HelpItem &help = lastHelpItemIdentified();
|
||||
if (help.isValid()) {
|
||||
const QString text = CppTools::CppHoverHandler::tooltipTextForHelpItem(help);
|
||||
if (!text.isEmpty())
|
||||
setToolTip(text);
|
||||
}
|
||||
}
|
||||
|
||||
void ClangHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget,
|
||||
const QPoint &point)
|
||||
{
|
||||
if (priority() == Priority_Diagnostic) {
|
||||
const HelpItem helpItem = lastHelpItemIdentified();
|
||||
const QString helpId = helpItem.isValid() ? helpItem.helpId() : QString();
|
||||
processWithEditorDocumentProcessor(editorWidget, point, m_cursorPosition, helpId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Priority_Tooltip / Priority_Help
|
||||
BaseHoverHandler::operateTooltip(editorWidget, point);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
60
src/plugins/clangcodemodel/clanghoverhandler.h
Normal file
60
src/plugins/clangcodemodel/clanghoverhandler.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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/baseeditordocumentprocessor.h>
|
||||
#include <cpptools/cpphoverhandler.h>
|
||||
#include <texteditor/basehoverhandler.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class ClangHoverHandler : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(ClangHoverHandler)
|
||||
|
||||
public:
|
||||
ClangHoverHandler();
|
||||
~ClangHoverHandler() override;
|
||||
|
||||
void identifyMatchAsync(TextEditor::TextEditorWidget *editorWidget,
|
||||
int pos,
|
||||
ReportPriority report) override;
|
||||
void decorateToolTip() override;
|
||||
void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override;
|
||||
|
||||
private:
|
||||
void cancelAsyncCheck() override;
|
||||
void processToolTipInfo(const CppTools::ToolTipInfo &info);
|
||||
|
||||
private:
|
||||
int m_cursorPosition = -1;
|
||||
QScopedPointer<QFutureWatcher<CppTools::ToolTipInfo>> m_futureWatcher;
|
||||
ReportPriority m_reportPriority;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
@@ -29,11 +29,11 @@
|
||||
#include "clangeditordocumentprocessor.h"
|
||||
#include "clangutils.h"
|
||||
#include "clangfollowsymbol.h"
|
||||
#include "clanghoverhandler.h"
|
||||
#include "clangrefactoringengine.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <cpptools/cppfollowsymbolundercursor.h>
|
||||
#include <cpptools/cpphoverhandler.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/editordocumenthandle.h>
|
||||
#include <cpptools/projectinfo.h>
|
||||
@@ -114,7 +114,7 @@ CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssis
|
||||
|
||||
TextEditor::BaseHoverHandler *ModelManagerSupportClang::createHoverHandler()
|
||||
{
|
||||
return new CppTools::CppHoverHandler;
|
||||
return new Internal::ClangHoverHandler;
|
||||
}
|
||||
|
||||
CppTools::FollowSymbolInterface &ModelManagerSupportClang::followSymbolInterface()
|
||||
|
@@ -97,6 +97,13 @@ void BaseEditorDocumentProcessor::setParserConfig(
|
||||
parser()->setConfiguration(config);
|
||||
}
|
||||
|
||||
QFuture<ToolTipInfo> BaseEditorDocumentProcessor::toolTipInfo(const QByteArray &/*codecName*/,
|
||||
int /*line*/,
|
||||
int /*column*/)
|
||||
{
|
||||
return QFuture<ToolTipInfo>();
|
||||
}
|
||||
|
||||
void BaseEditorDocumentProcessor::runParser(QFutureInterface<void> &future,
|
||||
BaseEditorDocumentParser::Ptr parser,
|
||||
BaseEditorDocumentParser::UpdateParams updateParams)
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "cpptools_global.h"
|
||||
|
||||
#include <texteditor/codeassist/assistinterface.h>
|
||||
#include <texteditor/helpitem.h>
|
||||
#include <texteditor/quickfix.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
@@ -48,6 +49,18 @@ class TextDocument;
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
// For clang code model only, move?
|
||||
struct CPPTOOLS_EXPORT ToolTipInfo {
|
||||
QString text;
|
||||
QString briefComment;
|
||||
|
||||
QStringList qDocIdCandidates;
|
||||
QString qDocMark;
|
||||
TextEditor::HelpItem::Category qDocCategory;
|
||||
|
||||
QString sizeInBytes;
|
||||
};
|
||||
|
||||
class CPPTOOLS_EXPORT BaseEditorDocumentProcessor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -78,6 +91,7 @@ public:
|
||||
virtual QFuture<CursorInfo> cursorInfo(const CursorInfoParams ¶ms) = 0;
|
||||
virtual QFuture<CursorInfo> requestLocalReferences(const QTextCursor &cursor) = 0;
|
||||
virtual QFuture<SymbolInfo> requestFollowSymbol(int line, int column) = 0;
|
||||
virtual QFuture<ToolTipInfo> toolTipInfo(const QByteArray &codecName, int line, int column);
|
||||
|
||||
public:
|
||||
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||
|
@@ -28,78 +28,47 @@
|
||||
#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 {
|
||||
|
||||
QString CppHoverHandler::tooltipTextForHelpItem(const HelpItem &helpItem)
|
||||
{
|
||||
// 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 = helpItem.category();
|
||||
const QString &contents = helpItem.extractContent(false);
|
||||
if (!contents.isEmpty()) {
|
||||
if (category == HelpItem::ClassOrNamespace)
|
||||
return helpItem.helpId() + contents;
|
||||
else
|
||||
return 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 ");
|
||||
return prefix + helpItem.helpId();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -135,9 +104,6 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
||||
|
||||
void CppHoverHandler::decorateToolTip()
|
||||
{
|
||||
if (m_positionForEditorDocumentProcessor != -1)
|
||||
return;
|
||||
|
||||
if (Qt::mightBeRichText(toolTip()))
|
||||
setToolTip(toolTip().toHtmlEscaped());
|
||||
|
||||
@@ -146,42 +112,10 @@ void CppHoverHandler::decorateToolTip()
|
||||
|
||||
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());
|
||||
}
|
||||
const QString text = tooltipTextForHelpItem(help);
|
||||
if (!text.isEmpty())
|
||||
setToolTip(text);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@@ -33,13 +33,12 @@ namespace CppTools {
|
||||
|
||||
class CPPTOOLS_EXPORT CppHoverHandler : public TextEditor::BaseHoverHandler
|
||||
{
|
||||
public:
|
||||
static QString tooltipTextForHelpItem(const TextEditor::HelpItem &help);
|
||||
|
||||
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
|
||||
|
@@ -309,6 +309,7 @@ public:
|
||||
const int documentRevision = textCursor.document()->revision();
|
||||
const int position = Text::wordStartCursor(textCursor).position();
|
||||
if (m_lastHandlerInfo.applies(documentRevision, position)) {
|
||||
qDebug() << "Last handler applies, showing it";
|
||||
m_lastHandlerInfo.handler->showToolTip(m_widget, point, /*decorate=*/ false);
|
||||
return;
|
||||
}
|
||||
@@ -364,6 +365,7 @@ public:
|
||||
|
||||
// All were queried, run the best
|
||||
if (m_bestHandler) {
|
||||
qDebug() << "setting last handler info:" << m_documentRevision << m_position;
|
||||
m_lastHandlerInfo = LastHandlerInfo(m_bestHandler, m_documentRevision, m_position);
|
||||
m_bestHandler->showToolTip(m_widget, m_point);
|
||||
}
|
||||
|
@@ -36,4 +36,9 @@ enum class PreferredTranslationUnit
|
||||
LastUninitialized,
|
||||
};
|
||||
|
||||
// CLANG-UPGRADE-CHECK: Remove IS_SUSPEND_SUPPORTED once we require clang >= 7.0
|
||||
#if defined(CINDEX_VERSION_HAS_PRETTYDECL_BACKPORTED) || CINDEX_VERSION_MINOR >= 47
|
||||
# define IS_PRETTY_DECL_SUPPORTED
|
||||
#endif
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
@@ -29,10 +29,12 @@ HEADERS += \
|
||||
$$PWD/clangreparsesupportivetranslationunitjob.h \
|
||||
$$PWD/clangrequestdocumentannotationsjob.h \
|
||||
$$PWD/clangrequestreferencesjob.h \
|
||||
$$PWD/clangrequesttooltipjob.h \
|
||||
$$PWD/clangresumedocumentjob.h \
|
||||
$$PWD/clangstring.h \
|
||||
$$PWD/clangsupportivetranslationunitinitializer.h \
|
||||
$$PWD/clangsuspenddocumentjob.h \
|
||||
$$PWD/clangtooltipinfocollector.h \
|
||||
$$PWD/clangtranslationunit.h \
|
||||
$$PWD/clangtranslationunits.h \
|
||||
$$PWD/clangtranslationunitupdater.h \
|
||||
@@ -86,8 +88,10 @@ SOURCES += \
|
||||
$$PWD/clangreparsesupportivetranslationunitjob.cpp \
|
||||
$$PWD/clangrequestdocumentannotationsjob.cpp \
|
||||
$$PWD/clangrequestreferencesjob.cpp \
|
||||
$$PWD/clangrequesttooltipjob.cpp \
|
||||
$$PWD/clangsuspenddocumentjob.cpp \
|
||||
$$PWD/clangsupportivetranslationunitinitializer.cpp \
|
||||
$$PWD/clangtooltipinfocollector.cpp \
|
||||
$$PWD/clangtranslationunit.cpp \
|
||||
$$PWD/clangtranslationunits.cpp \
|
||||
$$PWD/clangtranslationunitupdater.cpp \
|
||||
|
@@ -258,6 +258,7 @@ static void fillJobRequest(JobRequest &jobRequest, const MessageType &message)
|
||||
jobRequest.line = message.line();
|
||||
jobRequest.column = message.column();
|
||||
jobRequest.ticketNumber = message.ticketNumber();
|
||||
jobRequest.textCodecName = message.fileContainer().textCodecName();
|
||||
// The unsaved files might get updater later, so take the current
|
||||
// revision for the request.
|
||||
jobRequest.documentRevision = message.fileContainer().documentRevision();
|
||||
@@ -303,6 +304,25 @@ void ClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMessage
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::requestToolTip(const RequestToolTipMessage &message)
|
||||
{
|
||||
TIME_SCOPE_DURATION("ClangCodeModelServer::requestToolTip");
|
||||
|
||||
try {
|
||||
const Document document = documents.document(message.fileContainer().filePath(),
|
||||
message.fileContainer().projectPartId());
|
||||
DocumentProcessor processor = documentProcessors().processor(document);
|
||||
|
||||
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestToolTip);
|
||||
fillJobRequest(jobRequest, message);
|
||||
|
||||
processor.addJob(jobRequest);
|
||||
processor.process();
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in ClangCodeModelServer::requestToolTip:" << exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
qCDebug(serverLog) << "########## updateVisibleTranslationUnits";
|
||||
|
@@ -61,6 +61,7 @@ public:
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const RequestReferencesMessage &message) override;
|
||||
void requestFollowSymbol(const RequestFollowSymbolMessage &message) override;
|
||||
void requestToolTip(const RequestToolTipMessage &message) override;
|
||||
|
||||
public: // for tests
|
||||
const Documents &documentsForTestOnly() const;
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "clangreparsesupportivetranslationunitjob.h"
|
||||
#include "clangrequestdocumentannotationsjob.h"
|
||||
#include "clangrequestreferencesjob.h"
|
||||
#include "clangrequesttooltipjob.h"
|
||||
#include "clangresumedocumentjob.h"
|
||||
#include "clangsuspenddocumentjob.h"
|
||||
#include "clangupdatedocumentannotationsjob.h"
|
||||
@@ -40,6 +41,7 @@
|
||||
#include <clangsupport/cmbcodecompletedmessage.h>
|
||||
#include <clangsupport/followsymbolmessage.h>
|
||||
#include <clangsupport/referencesmessage.h>
|
||||
#include <clangsupport/tooltipmessage.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -62,6 +64,7 @@ static const char *JobRequestTypeToText(JobRequest::Type type)
|
||||
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
|
||||
RETURN_TEXT_FOR_CASE(RequestReferences);
|
||||
RETURN_TEXT_FOR_CASE(FollowSymbol);
|
||||
RETURN_TEXT_FOR_CASE(RequestToolTip);
|
||||
RETURN_TEXT_FOR_CASE(SuspendDocument);
|
||||
RETURN_TEXT_FOR_CASE(ResumeDocument);
|
||||
}
|
||||
@@ -126,6 +129,7 @@ static JobRequest::ExpirationConditions expirationConditionsForType(JobRequest::
|
||||
return Conditions(Condition::AnythingChanged);
|
||||
case Type::RequestReferences:
|
||||
case Type::RequestDocumentAnnotations:
|
||||
case Type::RequestToolTip:
|
||||
case Type::FollowSymbol:
|
||||
return Conditions(Condition::DocumentClosed)
|
||||
| Conditions(Condition::DocumentRevisionChanged);
|
||||
@@ -153,8 +157,10 @@ static JobRequest::RunConditions conditionsForType(JobRequest::Type type)
|
||||
Conditions conditions = Conditions(Condition::DocumentUnsuspended)
|
||||
| Conditions(Condition::DocumentVisible);
|
||||
|
||||
if (type == Type::RequestReferences || type == Type::FollowSymbol)
|
||||
if (type == Type::RequestReferences || type == Type::FollowSymbol
|
||||
|| type == Type::RequestToolTip) {
|
||||
conditions |= Condition::CurrentDocumentRevision;
|
||||
}
|
||||
|
||||
if (type != Type::UpdateDocumentAnnotations && type != Type::ParseSupportiveTranslationUnit)
|
||||
conditions |= Condition::DocumentParsed;
|
||||
@@ -192,6 +198,8 @@ IAsyncJob *JobRequest::createJob() const
|
||||
return new RequestDocumentAnnotationsJob();
|
||||
case JobRequest::Type::RequestReferences:
|
||||
return new RequestReferencesJob();
|
||||
case JobRequest::Type::RequestToolTip:
|
||||
return new RequestToolTipJob();
|
||||
case JobRequest::Type::FollowSymbol:
|
||||
return new FollowSymbolJob();
|
||||
case JobRequest::Type::SuspendDocument:
|
||||
@@ -224,6 +232,11 @@ void JobRequest::cancelJob(ClangCodeModelClientInterface &client) const
|
||||
false,
|
||||
ticketNumber));
|
||||
break;
|
||||
case JobRequest::Type::RequestToolTip:
|
||||
client.tooltip(ToolTipMessage(FileContainer(),
|
||||
ToolTipInfo(),
|
||||
ticketNumber));
|
||||
break;
|
||||
case JobRequest::Type::CompleteCode:
|
||||
client.codeCompleted(CodeCompletedMessage(CodeCompletions(),
|
||||
CompletionCorrection::NoCorrection,
|
||||
|
@@ -59,6 +59,7 @@ public:
|
||||
RequestDocumentAnnotations,
|
||||
RequestReferences,
|
||||
FollowSymbol,
|
||||
RequestToolTip,
|
||||
|
||||
SuspendDocument,
|
||||
ResumeDocument,
|
||||
@@ -118,6 +119,7 @@ public:
|
||||
qint32 funcNameStartLine = -1;
|
||||
qint32 funcNameStartColumn = -1;
|
||||
quint64 ticketNumber = 0;
|
||||
Utf8String textCodecName;
|
||||
bool localReferences = false;
|
||||
};
|
||||
|
||||
|
67
src/tools/clangbackend/source/clangrequesttooltipjob.cpp
Normal file
67
src/tools/clangbackend/source/clangrequesttooltipjob.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "clangrequesttooltipjob.h"
|
||||
|
||||
#include <clangsupport/clangsupportdebugutils.h>
|
||||
#include <clangsupport/clangcodemodelclientinterface.h>
|
||||
#include <clangsupport/tooltipmessage.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
IAsyncJob::AsyncPrepareResult RequestToolTipJob::prepareAsyncRun()
|
||||
{
|
||||
const JobRequest jobRequest = context().jobRequest;
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestToolTip, return AsyncPrepareResult());
|
||||
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
|
||||
|
||||
const TranslationUnit translationUnit = *m_translationUnit;
|
||||
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
|
||||
const quint32 line = jobRequest.line;
|
||||
const quint32 column = jobRequest.column;
|
||||
const Utf8String textCodecName = jobRequest.textCodecName;
|
||||
setRunner([translationUnit, unsavedFiles, line, column, textCodecName]() {
|
||||
TIME_SCOPE_DURATION("RequestToolTipJobRunner");
|
||||
|
||||
UnsavedFiles theUnsavedFiles = unsavedFiles;
|
||||
return translationUnit.tooltip(theUnsavedFiles, textCodecName, line, column);
|
||||
});
|
||||
return AsyncPrepareResult{translationUnit.id()};
|
||||
}
|
||||
|
||||
void RequestToolTipJob::finalizeAsyncRun()
|
||||
{
|
||||
if (!context().isOutdated()) {
|
||||
const AsyncResult result = asyncResult();
|
||||
|
||||
context().client->tooltip(ToolTipMessage(m_pinnedFileContainer,
|
||||
result,
|
||||
context().jobRequest.ticketNumber));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
43
src/tools/clangbackend/source/clangrequesttooltipjob.h
Normal file
43
src/tools/clangbackend/source/clangrequesttooltipjob.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 <clangsupport/tooltipinfo.h>
|
||||
|
||||
#include "clangdocumentjob.h"
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class RequestToolTipJob : public DocumentJob<ToolTipInfo>
|
||||
{
|
||||
public:
|
||||
using AsyncResult = ToolTipInfo;
|
||||
|
||||
AsyncPrepareResult prepareAsyncRun() override;
|
||||
void finalizeAsyncRun() override;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
531
src/tools/clangbackend/source/clangtooltipinfocollector.cpp
Normal file
531
src/tools/clangbackend/source/clangtooltipinfocollector.cpp
Normal file
@@ -0,0 +1,531 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "clangtooltipinfocollector.h"
|
||||
|
||||
#include "clangbackend_global.h"
|
||||
#include "clangstring.h"
|
||||
#include "cursor.h"
|
||||
#include "sourcerange.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "unsavedfile.h"
|
||||
|
||||
#include <clangsupport/sourcerangecontainer.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/textfileformat.h>
|
||||
|
||||
#include <utf8string.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QTextCodec>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
namespace {
|
||||
|
||||
Utf8StringVector qualificationPrefixAsVector(const Cursor &cursor)
|
||||
{
|
||||
Utf8StringVector result;
|
||||
|
||||
for (Cursor parent = cursor.semanticParent();
|
||||
parent.isValid() && (parent.kind() == CXCursor_Namespace || parent.isCompoundType());
|
||||
parent = parent.semanticParent()) {
|
||||
result.prepend(parent.spelling());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Utf8String qualificationPrefix(const Cursor &cursor)
|
||||
{
|
||||
// TODO: Implement with qualificationPrefixAsVector()
|
||||
Utf8String qualifiedName;
|
||||
|
||||
for (Cursor parent = cursor.semanticParent();
|
||||
parent.isValid() && (parent.kind() == CXCursor_Namespace);
|
||||
parent = parent.semanticParent()) {
|
||||
qualifiedName = parent.spelling() + Utf8StringLiteral("::") + qualifiedName;
|
||||
}
|
||||
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
Utf8String displayName(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.kind() == CXCursor_ClassTemplate) {
|
||||
// TODO: The qualification should be part of the display name. Fix this in libclang.
|
||||
return qualificationPrefix(cursor) + cursor.displayName();
|
||||
}
|
||||
|
||||
return cursor.displayName();
|
||||
}
|
||||
|
||||
Utf8String textForFunctionLike(const Cursor &cursor)
|
||||
{
|
||||
#ifdef IS_PRETTY_DECL_SUPPORTED
|
||||
CXPrintingPolicy policy = clang_getCursorPrintingPolicy(cursor.cx());
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_FullyQualifiedName, 1);
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_TerseOutput, 1);
|
||||
// Avoid printing attributes/pragmas
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_PolishForDeclaration, 1);
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_SuppressInitializers, 1);
|
||||
const Utf8String prettyPrinted = ClangString(
|
||||
clang_getCursorPrettyPrinted(cursor.cx(), policy));
|
||||
clang_PrintingPolicy_dispose(policy);
|
||||
return prettyPrinted;
|
||||
#else
|
||||
// Printing function declarations with displayName() is quite limited:
|
||||
// * result type is not included
|
||||
// * parameter names are not included
|
||||
// * templates in the result type are not included
|
||||
// * no full qualification of the function name
|
||||
return Utf8String(cursor.resultType().spelling())
|
||||
+ Utf8StringLiteral(" ")
|
||||
+ qualificationPrefix(cursor)
|
||||
+ Utf8String(cursor.displayName());
|
||||
#endif
|
||||
}
|
||||
|
||||
Utf8String textForEnumConstantDecl(const Cursor &cursor)
|
||||
{
|
||||
const Cursor semanticParent = cursor.semanticParent();
|
||||
QTC_ASSERT(semanticParent.kind() == CXCursor_EnumDecl, return Utf8String());
|
||||
|
||||
const Type enumType = semanticParent.enumType();
|
||||
if (enumType.isUnsigned())
|
||||
return Utf8String::number(cursor.enumConstantUnsignedValue());
|
||||
return Utf8String::number(cursor.enumConstantValue());
|
||||
}
|
||||
|
||||
Utf8String textForInclusionDirective(const Cursor &cursor)
|
||||
{
|
||||
const CXFile includedFile = cursor.includedFile();
|
||||
const Utf8String fileName = ClangString(clang_getFileName(includedFile));
|
||||
|
||||
return QDir::toNativeSeparators(fileName.toString());
|
||||
}
|
||||
|
||||
Utf8String textForAnyTypeAlias(const Cursor &cursor)
|
||||
{
|
||||
// For a CXCursor_TypeAliasTemplateDecl the type of cursor/referenced
|
||||
// is invalid, so we do not get the underlying type. This here solely
|
||||
// reports the unresolved name instead of the empty string.
|
||||
if (cursor.kind() == CXCursor_TypeAliasTemplateDecl)
|
||||
return cursor.displayName();
|
||||
|
||||
return cursor.type().alias().utf8Spelling();
|
||||
}
|
||||
|
||||
bool includeSizeForCursor(const Cursor &cursor)
|
||||
{
|
||||
return cursor.isCompoundType()
|
||||
|| cursor.kind() == CXCursor_EnumDecl
|
||||
|| cursor.kind() == CXCursor_UnionDecl
|
||||
|| cursor.kind() == CXCursor_FieldDecl;
|
||||
}
|
||||
|
||||
Utf8String sizeInBytes(const Cursor &cursor)
|
||||
{
|
||||
if (includeSizeForCursor(cursor)) {
|
||||
bool ok = false;
|
||||
const long long size = cursor.type().sizeOf(&ok);
|
||||
if (ok)
|
||||
return Utf8String::number(size);
|
||||
}
|
||||
|
||||
return Utf8String();
|
||||
}
|
||||
|
||||
Cursor referencedCursor(const Cursor &cursor)
|
||||
{
|
||||
// Query the referenced cursor directly instead of first testing with cursor.isReference().
|
||||
// cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr
|
||||
// although it returns a valid cursor.
|
||||
const Cursor referenced = cursor.referenced();
|
||||
if (referenced.isValid())
|
||||
return referenced;
|
||||
|
||||
const Cursor definition = cursor.definition();
|
||||
if (definition.isValid())
|
||||
return definition;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
class ToolTipInfoCollector
|
||||
{
|
||||
public:
|
||||
ToolTipInfoCollector(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit);
|
||||
|
||||
ToolTipInfo collect(uint line, uint column) const;
|
||||
|
||||
private:
|
||||
Utf8String text(const Cursor &cursor, const Cursor &referenced) const;
|
||||
Utf8String textForMacroExpansion(const Cursor &cursor) const;
|
||||
Utf8String textForNamespaceAlias(const Cursor &cursor) const;
|
||||
|
||||
ToolTipInfo qDocInfo(const Cursor &cursor) const;
|
||||
|
||||
CXSourceLocation toCXSourceLocation(uint line, uint column) const;
|
||||
|
||||
UnsavedFile unsavedFile(const Utf8String &filePath) const;
|
||||
Utf8String lineRange(const Utf8String &filePath, unsigned fromLine, unsigned toLine) const;
|
||||
|
||||
private:
|
||||
UnsavedFiles &m_unsavedFiles;
|
||||
const Utf8String m_textCodecName;
|
||||
|
||||
const Utf8String m_mainFilePath;
|
||||
CXTranslationUnit m_cxTranslationUnit = nullptr;
|
||||
|
||||
};
|
||||
|
||||
ToolTipInfoCollector::ToolTipInfoCollector(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit)
|
||||
: m_unsavedFiles(unsavedFiles)
|
||||
, m_textCodecName(textCodecName)
|
||||
, m_mainFilePath(mainFilePath)
|
||||
, m_cxTranslationUnit(cxTranslationUnit)
|
||||
{
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::text(const Cursor &cursor, const Cursor &referenced) const
|
||||
{
|
||||
if (cursor.kind() == CXCursor_MacroExpansion)
|
||||
return textForMacroExpansion(referenced);
|
||||
|
||||
if (referenced.kind() == CXCursor_EnumConstantDecl)
|
||||
return textForEnumConstantDecl(referenced);
|
||||
|
||||
if (referenced.kind() == CXCursor_InclusionDirective)
|
||||
return textForInclusionDirective(referenced);
|
||||
|
||||
if (referenced.kind() == CXCursor_Namespace)
|
||||
return qualificationPrefix(referenced) + referenced.spelling();
|
||||
|
||||
if (referenced.kind() == CXCursor_NamespaceAlias)
|
||||
return textForNamespaceAlias(referenced);
|
||||
|
||||
if (referenced.isAnyTypeAlias())
|
||||
return textForAnyTypeAlias(referenced);
|
||||
|
||||
if (referenced.isFunctionLike())
|
||||
return textForFunctionLike(referenced);
|
||||
|
||||
if (referenced.type().canonical().isBuiltinType())
|
||||
return referenced.type().canonical().builtinTypeToString();
|
||||
|
||||
if (referenced.kind() == CXCursor_VarDecl)
|
||||
return referenced.type().spelling(); // e.g. "Zii<int>"
|
||||
|
||||
const Type referencedType = referenced.type();
|
||||
if (referencedType.isValid()) {
|
||||
// Generally, the type includes the qualification but has this limitations:
|
||||
// * namespace aliases are not resolved
|
||||
// * outer class of a inner template class is not included
|
||||
// The type includes the qualification, but not resolved namespace aliases.
|
||||
|
||||
// For a CXType_Record, this also includes e.g. "const " as prefix.
|
||||
return referencedType.canonical().utf8Spelling();
|
||||
}
|
||||
|
||||
return displayName(referenced);
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::textForMacroExpansion(const Cursor &cursor) const
|
||||
{
|
||||
QTC_ASSERT(cursor.kind() == CXCursor_MacroDefinition, return Utf8String());
|
||||
|
||||
const SourceRange sourceRange = cursor.sourceRange();
|
||||
const SourceLocation start = sourceRange.start();
|
||||
const SourceLocation end = sourceRange.end();
|
||||
|
||||
return lineRange(start.filePath(), start.line(), end.line());
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::textForNamespaceAlias(const Cursor &cursor) const
|
||||
{
|
||||
// TODO: Add some libclang API to get the aliased name straight away.
|
||||
|
||||
CXToken *cxTokens = nullptr;
|
||||
uint cxTokenCount = 0;
|
||||
|
||||
clang_tokenize(m_cxTranslationUnit, cursor.cxSourceRange(), &cxTokens, &cxTokenCount);
|
||||
|
||||
Utf8String aliasedName;
|
||||
// Start at 3 in order to skip these tokens: namespace X =
|
||||
for (uint i = 3; i < cxTokenCount; ++i)
|
||||
aliasedName += ClangString(clang_getTokenSpelling(m_cxTranslationUnit, cxTokens[i]));
|
||||
|
||||
clang_disposeTokens(m_cxTranslationUnit, cxTokens, cxTokenCount);
|
||||
|
||||
return aliasedName;
|
||||
}
|
||||
|
||||
static Utf8String typeName(const Type &type)
|
||||
{
|
||||
return type.declaration().spelling();
|
||||
}
|
||||
|
||||
static Utf8String qdocMark(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.kind() == CXCursor_ClassTemplate)
|
||||
return cursor.spelling();
|
||||
|
||||
if (cursor.type().kind() == CXType_Enum
|
||||
|| cursor.type().kind() == CXType_Typedef
|
||||
|| cursor.type().kind() == CXType_Record)
|
||||
return typeName(cursor.type());
|
||||
|
||||
Utf8String text = cursor.displayName();
|
||||
if (cursor.kind() == CXCursor_FunctionDecl) {
|
||||
// TODO: Remove this workaround by fixing this in
|
||||
// libclang with the help of CXPrintingPolicy.
|
||||
text.replace(Utf8StringLiteral("<>"), Utf8String());
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static ToolTipInfo::QdocCategory qdocCategory(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.isFunctionLike())
|
||||
return ToolTipInfo::Function;
|
||||
|
||||
if (cursor.kind() == CXCursor_MacroDefinition)
|
||||
return ToolTipInfo::Macro;
|
||||
|
||||
if (cursor.kind() == CXCursor_EnumConstantDecl)
|
||||
return ToolTipInfo::Enum;
|
||||
|
||||
if (cursor.type().kind() == CXType_Enum)
|
||||
return ToolTipInfo::Enum;
|
||||
|
||||
if (cursor.kind() == CXCursor_InclusionDirective)
|
||||
return ToolTipInfo::Brief;
|
||||
|
||||
// TODO: Handle CXCursor_NamespaceAlias, too?!
|
||||
if (cursor.kind() == CXCursor_Namespace)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.isCompoundType())
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.kind() == CXCursor_NamespaceAlias)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.type().kind() == CXType_Typedef)
|
||||
return ToolTipInfo::Typedef;
|
||||
|
||||
if (cursor.type().kind() == CXType_Record)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.kind() == CXCursor_TypeAliasTemplateDecl)
|
||||
return ToolTipInfo::Typedef;
|
||||
|
||||
if (cursor.kind() == CXCursor_ClassTemplate)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
return ToolTipInfo::Unknown;
|
||||
}
|
||||
|
||||
static Utf8String name(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.type().kind() == CXType_Record || cursor.kind() == CXCursor_EnumDecl)
|
||||
return typeName(cursor.type());
|
||||
|
||||
return cursor.spelling();
|
||||
}
|
||||
|
||||
static Utf8StringVector qDocIdCandidates(const Cursor &cursor)
|
||||
{
|
||||
Utf8StringVector components = qualificationPrefixAsVector(cursor);
|
||||
if (components.isEmpty())
|
||||
return { name(cursor) };
|
||||
|
||||
components << name(cursor);
|
||||
Utf8StringVector result;
|
||||
Utf8String name;
|
||||
for (auto it = components.rbegin(); it != components.rend(); ++it) {
|
||||
if (name.isEmpty())
|
||||
name = *it;
|
||||
else
|
||||
name = *it + (Utf8StringLiteral("::") + name);
|
||||
|
||||
result.prepend(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Add libclang API for this?!
|
||||
static bool isBuiltinOrPointerToBuiltin(const Type &type)
|
||||
{
|
||||
Type theType = type;
|
||||
|
||||
if (theType.isBuiltinType())
|
||||
return true;
|
||||
|
||||
// TODO: Simplify
|
||||
// TODO: Test with **
|
||||
while (theType.pointeeType().isValid()) {
|
||||
theType = theType.pointeeType();
|
||||
if (theType.isBuiltinType())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ToolTipInfo ToolTipInfoCollector::qDocInfo(const Cursor &cursor) const
|
||||
{
|
||||
ToolTipInfo result;
|
||||
|
||||
if (isBuiltinOrPointerToBuiltin(cursor.type()))
|
||||
return result;
|
||||
|
||||
result.setQdocIdCandidates(qDocIdCandidates(cursor));
|
||||
result.setQdocMark(qdocMark(cursor));
|
||||
result.setQdocCategory(qdocCategory(cursor));
|
||||
|
||||
if (cursor.type().kind() == CXType_Record) {
|
||||
result.setQdocIdCandidates(qDocIdCandidates(cursor.type().declaration()));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cursor.kind() == CXCursor_VarDecl || cursor.kind() == CXCursor_FieldDecl) {
|
||||
result.setQdocMark(typeName(cursor.type()));
|
||||
// maybe template instantiation
|
||||
if (cursor.type().kind() == CXType_Unexposed && cursor.type().canonical().kind() == CXType_Record) {
|
||||
result.setQdocIdCandidates(qDocIdCandidates(cursor.type().canonical().declaration()));
|
||||
result.setQdocCategory(ToolTipInfo::ClassOrNamespace);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle also RValueReference()
|
||||
if (cursor.type().isLValueReference()) {
|
||||
const Cursor pointeeTypeDeclaration = cursor.type().pointeeType().declaration();
|
||||
result.setQdocIdCandidates(qDocIdCandidates(pointeeTypeDeclaration));
|
||||
result.setQdocMark(pointeeTypeDeclaration.spelling());
|
||||
result.setQdocCategory(qdocCategory(pointeeTypeDeclaration));
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CXSourceLocation ToolTipInfoCollector::toCXSourceLocation(uint line, uint column) const
|
||||
{
|
||||
return clang_getLocation(m_cxTranslationUnit,
|
||||
clang_getFile(m_cxTranslationUnit,
|
||||
m_mainFilePath.constData()),
|
||||
line,
|
||||
column);
|
||||
}
|
||||
|
||||
UnsavedFile ToolTipInfoCollector::unsavedFile(const Utf8String &filePath) const
|
||||
{
|
||||
const UnsavedFile &unsavedFile = m_unsavedFiles.unsavedFile(filePath);
|
||||
if (!unsavedFile.filePath().isEmpty())
|
||||
return unsavedFile;
|
||||
|
||||
// Create an unsaved file with the file content from disk.
|
||||
// TODO: Make use of clang_getFileContents() instead of reading from disk.
|
||||
QTextCodec *codec = QTextCodec::codecForName(m_textCodecName);
|
||||
QByteArray fileContent;
|
||||
QString errorString;
|
||||
using namespace Utils;
|
||||
const TextFileFormat::ReadResult readResult
|
||||
= TextFileFormat::readFileUTF8(filePath.toString(), codec, &fileContent, &errorString);
|
||||
if (readResult != TextFileFormat::ReadSuccess) {
|
||||
qWarning() << "Failed to read file" << filePath << ":" << errorString;
|
||||
return UnsavedFile();
|
||||
}
|
||||
|
||||
return UnsavedFile(filePath, Utf8String::fromByteArray(fileContent));
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::lineRange(const Utf8String &filePath,
|
||||
unsigned fromLine,
|
||||
unsigned toLine) const
|
||||
{
|
||||
if (toLine < fromLine)
|
||||
return Utf8String();
|
||||
|
||||
const UnsavedFile file = unsavedFile(filePath);
|
||||
if (file.fileContent().isEmpty())
|
||||
return Utf8String();
|
||||
|
||||
return file.lineRange(fromLine, toLine);
|
||||
}
|
||||
|
||||
ToolTipInfo ToolTipInfoCollector::collect(uint line, uint column) const
|
||||
{
|
||||
const Cursor cursor = clang_getCursor(m_cxTranslationUnit, toCXSourceLocation(line, column));
|
||||
if (!cursor.isValid())
|
||||
return ToolTipInfo(); // E.g. cursor on ifdeffed out range
|
||||
|
||||
const Cursor referenced = referencedCursor(cursor);
|
||||
QTC_CHECK(referenced.isValid());
|
||||
|
||||
ToolTipInfo info;
|
||||
info.setText(text(cursor, referenced));
|
||||
info.setBriefComment(referenced.briefComment());
|
||||
|
||||
{
|
||||
ToolTipInfo qDocToolTipInfo = qDocInfo(referenced);
|
||||
info.setQdocIdCandidates(qDocToolTipInfo.qdocIdCandidates());
|
||||
info.setQdocMark(qDocToolTipInfo.qdocMark());
|
||||
info.setQdocCategory(qDocToolTipInfo.qdocCategory());
|
||||
}
|
||||
|
||||
info.setSizeInBytes(sizeInBytes(cursor));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit,
|
||||
uint line,
|
||||
uint column)
|
||||
{
|
||||
ToolTipInfoCollector collector(unsavedFiles, textCodecName, mainFilePath, cxTranslationUnit);
|
||||
const ToolTipInfo info = collector.collect(line, column);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
45
src/tools/clangbackend/source/clangtooltipinfocollector.h
Normal file
45
src/tools/clangbackend/source/clangtooltipinfocollector.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 <utf8string.h>
|
||||
|
||||
#include <clangsupport/tooltipinfo.h>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class UnsavedFiles;
|
||||
|
||||
ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit,
|
||||
uint line,
|
||||
uint column);
|
||||
|
||||
} // namespace ClangBackEnd
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "clangbackend_global.h"
|
||||
#include "clangreferencescollector.h"
|
||||
#include "clangtooltipinfocollector.h"
|
||||
#include "clangtranslationunitupdater.h"
|
||||
#include "clangfollowsymbol.h"
|
||||
#include "clangfollowsymboljob.h"
|
||||
@@ -139,6 +140,20 @@ void TranslationUnit::extractDocumentAnnotations(
|
||||
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
|
||||
}
|
||||
|
||||
|
||||
ToolTipInfo TranslationUnit::tooltip(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
uint line,
|
||||
uint column) const
|
||||
{
|
||||
return collectToolTipInfo(unsavedFiles,
|
||||
textCodecName,
|
||||
filePath(),
|
||||
m_cxTranslationUnit,
|
||||
line,
|
||||
column);
|
||||
}
|
||||
|
||||
ReferencesResult TranslationUnit::references(uint line, uint column, bool localReferences) const
|
||||
{
|
||||
return collectReferences(m_cxTranslationUnit, line, column, localReferences);
|
||||
|
@@ -41,6 +41,7 @@ class SkippedSourceRanges;
|
||||
class SourceLocation;
|
||||
class SourceRange;
|
||||
class SourceRangeContainer;
|
||||
class ToolTipInfo;
|
||||
class TranslationUnitUpdateInput;
|
||||
class TranslationUnitUpdateResult;
|
||||
class UnsavedFiles;
|
||||
@@ -86,6 +87,10 @@ public:
|
||||
|
||||
|
||||
ReferencesResult references(uint line, uint column, bool localReferences = false) const;
|
||||
ToolTipInfo tooltip(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
uint line,
|
||||
uint column) const;
|
||||
DiagnosticSet diagnostics() const;
|
||||
|
||||
SourceLocation sourceLocationAt(uint line, uint column) const;
|
||||
|
@@ -84,6 +84,16 @@ bool Type::isBuiltinType() const
|
||||
return cxType.kind >= CXType_FirstBuiltin && cxType.kind <= CXType_LastBuiltin;
|
||||
}
|
||||
|
||||
bool Type::isUnsigned() const
|
||||
{
|
||||
return cxType.kind == CXType_UChar
|
||||
|| cxType.kind == CXType_UShort
|
||||
|| cxType.kind == CXType_UInt
|
||||
|| cxType.kind == CXType_ULong
|
||||
|| cxType.kind == CXType_ULongLong
|
||||
|| cxType.kind == CXType_UInt128;
|
||||
}
|
||||
|
||||
Utf8String Type::utf8Spelling() const
|
||||
{
|
||||
return ClangString(clang_getTypeSpelling(cxType));
|
||||
@@ -94,6 +104,83 @@ ClangString Type::spelling() const
|
||||
return ClangString(clang_getTypeSpelling(cxType));
|
||||
}
|
||||
|
||||
static const char *builtinTypeToText(CXTypeKind kind)
|
||||
{
|
||||
// CLANG-UPGRADE-CHECK: Check for added built-in types.
|
||||
|
||||
switch (kind) {
|
||||
case CXType_Void:
|
||||
return "void";
|
||||
case CXType_Bool:
|
||||
return "bool";
|
||||
|
||||
// See also ${CLANG_REPOSITORY}/lib/Sema/SemaChecking.cpp - IsSameCharType().
|
||||
case CXType_Char_U:
|
||||
case CXType_UChar:
|
||||
return "unsigned char";
|
||||
case CXType_Char_S:
|
||||
case CXType_SChar:
|
||||
return "signed char";
|
||||
|
||||
case CXType_Char16:
|
||||
return "char16_t";
|
||||
case CXType_Char32:
|
||||
return "char32_t";
|
||||
case CXType_WChar:
|
||||
return "wchar_t";
|
||||
|
||||
case CXType_UShort:
|
||||
return "unsigned short";
|
||||
case CXType_UInt:
|
||||
return "unsigned int";
|
||||
case CXType_ULong:
|
||||
return "unsigned long";
|
||||
case CXType_ULongLong:
|
||||
return "unsigned long long";
|
||||
case CXType_Short:
|
||||
return "short";
|
||||
|
||||
case CXType_Int:
|
||||
return "int";
|
||||
case CXType_Long:
|
||||
return "long";
|
||||
case CXType_LongLong:
|
||||
return "long long";
|
||||
|
||||
case CXType_Float:
|
||||
return "float";
|
||||
case CXType_Double:
|
||||
return "double";
|
||||
case CXType_LongDouble:
|
||||
return "long double";
|
||||
|
||||
case CXType_NullPtr:
|
||||
return "nullptr_t";
|
||||
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
|
||||
case CXType_Int128: return "__int128";
|
||||
case CXType_UInt128: return "unsigned __int128";
|
||||
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html
|
||||
case CXType_Float128: return "__float128";
|
||||
// CLANG-UPGRADE-CHECK: CXType_Float16 available with >= clang-6.0:
|
||||
// case CXType_Float16: return "_Float16";
|
||||
|
||||
// https://www.khronos.org/registry/OpenCL/sdk/2.1/docs/man/xhtml/scalarDataTypes.html
|
||||
case CXType_Half:
|
||||
return "half";
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Utf8String Type::builtinTypeToString() const
|
||||
{
|
||||
const char *text = builtinTypeToText(cxType.kind);
|
||||
return Utf8String::fromByteArray(QByteArray::fromRawData(text, strlen(text)));
|
||||
}
|
||||
|
||||
int Type::argumentCount() const
|
||||
{
|
||||
return clang_getNumArgTypes(cxType);
|
||||
@@ -129,6 +216,16 @@ Cursor Type::declaration() const
|
||||
return clang_getTypeDeclaration(cxType);
|
||||
}
|
||||
|
||||
long long Type::sizeOf(bool *isValid) const
|
||||
{
|
||||
const long long size = clang_Type_getSizeOf(cxType);
|
||||
*isValid = size != CXTypeLayoutError_Invalid
|
||||
&& size != CXTypeLayoutError_Incomplete
|
||||
&& size != CXTypeLayoutError_Dependent;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
CXTypeKind Type::kind() const
|
||||
{
|
||||
return cxType.kind;
|
||||
|
@@ -53,9 +53,11 @@ public:
|
||||
bool isReferencingConstant() const;
|
||||
bool isOutputArgument() const;
|
||||
bool isBuiltinType() const;
|
||||
bool isUnsigned() const;
|
||||
|
||||
Utf8String utf8Spelling() const;
|
||||
ClangString spelling() const;
|
||||
Utf8String builtinTypeToString() const;
|
||||
int argumentCount() const;
|
||||
|
||||
Type alias() const;
|
||||
@@ -66,6 +68,8 @@ public:
|
||||
|
||||
Cursor declaration() const;
|
||||
|
||||
long long sizeOf(bool *isValid) const;
|
||||
|
||||
CXTypeKind kind() const;
|
||||
|
||||
private:
|
||||
|
@@ -158,6 +158,14 @@ bool Cursor::isTemplateLike() const
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
bool Cursor::isAnyTypeAlias() const
|
||||
{
|
||||
const CXCursorKind k = kind();
|
||||
return k == CXCursor_TypeAliasDecl
|
||||
|| k == CXCursor_TypedefDecl
|
||||
|| k == CXCursor_TypeAliasTemplateDecl;
|
||||
}
|
||||
|
||||
bool Cursor::hasFinalFunctionAttribute() const
|
||||
{
|
||||
bool hasFinal = false;
|
||||
@@ -248,11 +256,31 @@ Type Cursor::nonPointerTupe() const
|
||||
return typeResult;
|
||||
}
|
||||
|
||||
Type Cursor::enumType() const
|
||||
{
|
||||
return clang_getEnumDeclIntegerType(cxCursor);
|
||||
}
|
||||
|
||||
long long Cursor::enumConstantValue() const
|
||||
{
|
||||
return clang_getEnumConstantDeclValue(cxCursor);
|
||||
}
|
||||
|
||||
unsigned long long Cursor::enumConstantUnsignedValue() const
|
||||
{
|
||||
return clang_getEnumConstantDeclUnsignedValue(cxCursor);
|
||||
}
|
||||
|
||||
Cursor Cursor::specializedCursorTemplate() const
|
||||
{
|
||||
return clang_getSpecializedCursorTemplate(cxCursor);
|
||||
}
|
||||
|
||||
CXFile Cursor::includedFile() const
|
||||
{
|
||||
return clang_getIncludedFile(cxCursor);
|
||||
}
|
||||
|
||||
SourceLocation Cursor::sourceLocation() const
|
||||
{
|
||||
return clang_getCursorLocation(cxCursor);
|
||||
@@ -341,6 +369,11 @@ Cursor Cursor::functionBase() const
|
||||
return functionBaseCursor;
|
||||
}
|
||||
|
||||
Type Cursor::resultType() const
|
||||
{
|
||||
return clang_getResultType(type().cxType);
|
||||
}
|
||||
|
||||
Cursor Cursor::argument(int index) const
|
||||
{
|
||||
return clang_Cursor_getArgument(cxCursor, index);
|
||||
@@ -398,6 +431,11 @@ CXCursorKind Cursor::kind() const
|
||||
return clang_getCursorKind(cxCursor);
|
||||
}
|
||||
|
||||
CXCursor Cursor::cx() const
|
||||
{
|
||||
return cxCursor;
|
||||
}
|
||||
|
||||
bool operator==(const Cursor &first, const Cursor &second)
|
||||
{
|
||||
return clang_equalCursors(first.cxCursor, second.cxCursor);
|
||||
|
@@ -67,6 +67,7 @@ public:
|
||||
bool isFunctionLike() const;
|
||||
bool isConstructorOrDestructor() const;
|
||||
bool isTemplateLike() const;
|
||||
bool isAnyTypeAlias() const;
|
||||
bool hasFinalFunctionAttribute() const;
|
||||
bool hasFinalClassAttribute() const;
|
||||
bool isUnexposed() const;
|
||||
@@ -81,6 +82,10 @@ public:
|
||||
|
||||
Type type() const;
|
||||
Type nonPointerTupe() const;
|
||||
Type enumType() const;
|
||||
|
||||
long long enumConstantValue() const;
|
||||
unsigned long long enumConstantUnsignedValue() const;
|
||||
|
||||
SourceLocation sourceLocation() const;
|
||||
CXSourceLocation cxSourceLocation() const;
|
||||
@@ -92,17 +97,19 @@ public:
|
||||
|
||||
Cursor definition() const;
|
||||
Cursor canonical() const;
|
||||
Cursor alias() const;
|
||||
Cursor referenced() const;
|
||||
Cursor semanticParent() const;
|
||||
Cursor lexicalParent() const;
|
||||
Cursor functionBaseDeclaration() const;
|
||||
Cursor functionBase() const;
|
||||
Type resultType() const;
|
||||
Cursor argument(int index) const;
|
||||
unsigned overloadedDeclarationsCount() const;
|
||||
Cursor overloadedDeclaration(unsigned index) const;
|
||||
Cursor specializedCursorTemplate() const;
|
||||
|
||||
CXFile includedFile() const;
|
||||
|
||||
void collectOutputArgumentRangesTo(
|
||||
std::vector<CXSourceRange> &outputArgumentRanges) const;
|
||||
std::vector<CXSourceRange> outputArgumentRanges() const;
|
||||
@@ -112,6 +119,8 @@ public:
|
||||
template <class VisitorCallback>
|
||||
void visit(VisitorCallback visitorCallback) const;
|
||||
|
||||
CXCursor cx() const;
|
||||
|
||||
private:
|
||||
CXCursor cxCursor;
|
||||
};
|
||||
|
@@ -30,6 +30,8 @@
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
UnsavedFile::UnsavedFile()
|
||||
@@ -79,6 +81,25 @@ bool UnsavedFile::hasCharacterAt(uint line, uint column, char character) const
|
||||
return positionIsOk && hasCharacterAt(utf8Position, character);
|
||||
}
|
||||
|
||||
Utf8String UnsavedFile::lineRange(uint fromLine, uint toLine) const
|
||||
{
|
||||
QTC_ASSERT(fromLine <= toLine, return Utf8String());
|
||||
|
||||
// Find start of first line
|
||||
bool ok = false;
|
||||
const uint fromPosition = toUtf8Position(fromLine, 1, &ok);
|
||||
QTC_ASSERT(ok, return Utf8String());
|
||||
|
||||
// Find end of last line
|
||||
uint toPosition = toUtf8Position(toLine, 1, &ok);
|
||||
QTC_ASSERT(ok, return Utf8String());
|
||||
const uint endPosition = uint(m_fileContent.byteSize());
|
||||
while (toPosition < endPosition && m_fileContent.constData()[toPosition] != '\n')
|
||||
++toPosition;
|
||||
|
||||
return m_fileContent.mid(int(fromPosition), int(toPosition - fromPosition));
|
||||
}
|
||||
|
||||
bool UnsavedFile::hasCharacterAt(uint position, char character) const
|
||||
{
|
||||
if (position < uint(m_fileContent.byteSize()))
|
||||
|
@@ -46,6 +46,7 @@ public:
|
||||
// 1-based line and column
|
||||
uint toUtf8Position(uint line, uint column, bool *ok) const;
|
||||
bool hasCharacterAt(uint line, uint column, char character) const;
|
||||
Utf8String lineRange(uint fromLine, uint toLine) const;
|
||||
|
||||
// 0-based position
|
||||
bool hasCharacterAt(uint position, char character) const;
|
||||
|
@@ -98,6 +98,11 @@ void EchoClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMess
|
||||
echoMessage(message);
|
||||
}
|
||||
|
||||
void EchoClangCodeModelServer::requestToolTip(const RequestToolTipMessage &message)
|
||||
{
|
||||
echoMessage(message);
|
||||
}
|
||||
|
||||
void EchoClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
echoMessage(message);
|
||||
|
@@ -47,6 +47,7 @@ public:
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const RequestReferencesMessage &message) override;
|
||||
void requestFollowSymbol(const RequestFollowSymbolMessage &message) override;
|
||||
void requestToolTip(const RequestToolTipMessage &message) override;
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
|
||||
private:
|
||||
|
628
tests/unit/unittest/clangtooltipinfo-test.cpp
Normal file
628
tests/unit/unittest/clangtooltipinfo-test.cpp
Normal file
@@ -0,0 +1,628 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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 "googletest.h"
|
||||
#include "rundocumentparse-utility.h"
|
||||
|
||||
#include <clangdocument.h>
|
||||
#include <clangdocuments.h>
|
||||
#include <clangsupport_global.h>
|
||||
#include <clangtooltipinfocollector.h>
|
||||
#include <clangtranslationunit.h>
|
||||
#include <fixitcontainer.h>
|
||||
#include <projectpart.h>
|
||||
#include <projects.h>
|
||||
#include <sourcelocationcontainer.h>
|
||||
#include <sourcerangecontainer.h>
|
||||
#include <unsavedfiles.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
using ::ClangBackEnd::ProjectPart;
|
||||
using ::ClangBackEnd::SourceLocationContainer;
|
||||
using ::ClangBackEnd::Document;
|
||||
using ::ClangBackEnd::UnsavedFiles;
|
||||
using ::ClangBackEnd::ToolTipInfo;
|
||||
using ::ClangBackEnd::SourceRangeContainer;
|
||||
|
||||
namespace {
|
||||
|
||||
#define CHECK_MEMBER(actual, expected, memberName) \
|
||||
if (actual.memberName() != expected.memberName()) { \
|
||||
*result_listener << #memberName " is " + PrintToString(actual.memberName()) \
|
||||
<< " and not " + PrintToString(expected.memberName()); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
MATCHER_P(IsToolTip, expected, std::string(negation ? "isn't" : "is") + PrintToString(expected))
|
||||
{
|
||||
CHECK_MEMBER(arg, expected, text);
|
||||
CHECK_MEMBER(arg, expected, briefComment);
|
||||
|
||||
CHECK_MEMBER(arg, expected, qdocIdCandidates);
|
||||
CHECK_MEMBER(arg, expected, qdocMark);
|
||||
CHECK_MEMBER(arg, expected, qdocCategory);
|
||||
|
||||
CHECK_MEMBER(arg, expected, sizeInBytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MATCHER_P(IsQdocToolTip, expected, std::string(negation ? "isn't" : "is") + PrintToString(expected))
|
||||
{
|
||||
CHECK_MEMBER(arg, expected, qdocIdCandidates);
|
||||
CHECK_MEMBER(arg, expected, qdocMark);
|
||||
CHECK_MEMBER(arg, expected, qdocCategory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef CHECK_MEMBER
|
||||
|
||||
struct Data {
|
||||
ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++14")}};
|
||||
ClangBackEnd::ProjectParts projects;
|
||||
ClangBackEnd::UnsavedFiles unsavedFiles;
|
||||
ClangBackEnd::Documents documents{projects, unsavedFiles};
|
||||
Document document{Utf8StringLiteral(TESTDATA_DIR "/tooltipinfo.cpp"),
|
||||
projectPart,
|
||||
{},
|
||||
documents};
|
||||
UnitTest::RunDocumentParse _1{document};
|
||||
};
|
||||
|
||||
class ToolTipInfo : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
::ToolTipInfo tooltip(uint line, uint column)
|
||||
{
|
||||
return d->document.translationUnit().tooltip(d->unsavedFiles,
|
||||
Utf8StringLiteral("UTF-8"),
|
||||
line,
|
||||
column);
|
||||
}
|
||||
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
private:
|
||||
static std::unique_ptr<Data> d;
|
||||
};
|
||||
|
||||
TEST_F(ToolTipInfo, LocalVariableInt)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(3, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("int"))));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, LocalVariablePointerToConstInt)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(4, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("const int *"))));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, LocalParameterVariableConstRefCustomType)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("const Foo &"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("Foo")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Foo"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(12, 12);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, LocalNonParameterVariableConstRefCustomType)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("const Foo"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("Foo")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Foo"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(14, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, MemberVariable)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(12, 16);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("int"))));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(MemberFunctionCall_QualifiedName))
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(21, 9);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("int Bar::mem()"));
|
||||
}
|
||||
|
||||
// ChangeLog: Show extra specifiers. For functions e.g.: virtual, inline, explicit, const, volatile
|
||||
TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(MemberFunctionCall_ExtraSpecifiers))
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(22, 9);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("virtual int Bar::virtualConstMem() const"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, MemberFunctionCall_qdocIdCandidates)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(21, 9);
|
||||
|
||||
ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("Bar::mem"),
|
||||
Utf8StringLiteral("mem")));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, MemberFunctionCall_qdocMark_FIXLIBCLANG_CHECKED)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(21, 9);
|
||||
|
||||
ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("mem()"));
|
||||
}
|
||||
|
||||
// TODO: Check what is really needed for qdoc before implementing this one.
|
||||
TEST_F(ToolTipInfo, DISABLED_MemberFunctionCall_qdocMark_extraSpecifiers)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(22, 9);
|
||||
|
||||
ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("virtualConstMem() const"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, MemberFunctionCall_qdocCategory)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(21, 9);
|
||||
|
||||
ASSERT_THAT(actual.qdocCategory(), ::ToolTipInfo::Function);
|
||||
}
|
||||
|
||||
// TODO: Show the template parameter type, too: "template<typename T>...)"
|
||||
TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(TemplateFunctionCall))
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(30, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("template<> void t<Foo>(int foo)"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TemplateFunctionCall_qdocIdCandidates)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(30, 5);
|
||||
|
||||
ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("t")));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TemplateFunctionCall_qdocMark_FIXLIBCLANG_CHECKED)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(30, 5);
|
||||
|
||||
ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("t(int)"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TemplateFunctionCall_qdocCategory)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(30, 5);
|
||||
|
||||
ASSERT_THAT(actual.qdocCategory(), ::ToolTipInfo::Function);
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, BriefComment)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(41, 5);
|
||||
|
||||
ASSERT_THAT(actual.briefComment(), Utf8StringLiteral("This is a crazy function."));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Enum)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("EnumType"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("EnumType")});
|
||||
expected.setQdocMark(Utf8StringLiteral("EnumType"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Enum);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(49, 12);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Enumerator)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("6"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("Custom")});
|
||||
expected.setQdocMark(Utf8StringLiteral("EnumType"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Enum);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(49, 22);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TemplateTypeFromParameter)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("const Baz<int> &"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("Baz")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Baz"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(55, 25);
|
||||
|
||||
ASSERT_THAT(actual, IsQdocToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TemplateTypeFromNonParameter)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("Baz<int>"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("Baz")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Baz"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(56, 19);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, IncludeDirective)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral(TESTDATA_DIR"/tooltipinfo.h"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("tooltipinfo.h")});
|
||||
expected.setQdocMark(Utf8StringLiteral("tooltipinfo.h"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Brief);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(59, 11);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, MacroUse_WithMacroFromSameFile)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(66, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("#define MACRO_FROM_MAINFILE(x) x + 3"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, MacroUse_WithMacroFromHeader)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(67, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("#define MACRO_FROM_HEADER(x) x + \\\n x + \\\n x"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, MacroUse_qdoc)
|
||||
{
|
||||
::ToolTipInfo expected;
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("MACRO_FROM_MAINFILE")});
|
||||
expected.setQdocMark(Utf8StringLiteral("MACRO_FROM_MAINFILE"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Macro);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(66, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsQdocToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDirectiveIsQualified)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("N::Muu"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Muu"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(77, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDirectiveOfAliasIsResolvedAndQualified)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("N::Muu"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Muu"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(82, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDeclarationIsQualified)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("N::Muu"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Muu"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(87, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, SizeForClassDefinition)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(92, 8);
|
||||
|
||||
ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("2"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, SizeForMemberField)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(95, 10);
|
||||
|
||||
ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("1"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, SizeForEnum)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(97, 12);
|
||||
|
||||
ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("4"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, SizeForUnion)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(98, 7);
|
||||
|
||||
ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("1"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Namespace)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("X"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("X")});
|
||||
expected.setQdocMark(Utf8StringLiteral("X"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(106, 11);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, NamespaceQualified)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("X::Y"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("X::Y"), Utf8StringLiteral("Y")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Y"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(107, 11);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
// TODO: Show unresolved and resolved name, for F1 try both.
|
||||
TEST_F(ToolTipInfo, TypeName_ResolveTypeDef)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("Ptr<Nuu>"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTypeDef")});
|
||||
expected.setQdocMark(Utf8StringLiteral("PtrFromTypeDef"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Typedef);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(122, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
// TODO: Show unresolved and resolved name, for F1 try both.
|
||||
TEST_F(ToolTipInfo, TypeName_ResolveAlias)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("Ptr<Nuu>"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTypeAlias")});
|
||||
expected.setQdocMark(Utf8StringLiteral("PtrFromTypeAlias"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Typedef);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(123, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
// The referenced cursor is a CXCursor_TypeAliasTemplateDecl, its type is invalid
|
||||
// and so probably clang_getTypedefDeclUnderlyingType() does not return anything useful.
|
||||
// TODO: Fix the cursor's type or add new API in libclang for querying the template type alias.
|
||||
TEST_F(ToolTipInfo, DISABLED_TypeName_ResolveTemplateTypeAlias)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(124, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("Ptr<Nuu>"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TypeName_ResolveTemplateTypeAlias_qdoc)
|
||||
{
|
||||
::ToolTipInfo expected;
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTemplateTypeAlias")});
|
||||
expected.setQdocMark(Utf8StringLiteral("PtrFromTemplateTypeAlias"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Typedef);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(124, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsQdocToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TemplateClassReference)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("Zii<T>"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("Zii")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Zii"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(134, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, TemplateClassQualified)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("U::Yii<T>"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("U::Yii"), Utf8StringLiteral("Yii")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Yii"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(135, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, ResolveNamespaceAliasForType)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("A::X"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("A::X"), Utf8StringLiteral("X")});
|
||||
expected.setQdocMark(Utf8StringLiteral("X"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(144, 8);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
// TODO: Show unresolved and resolved name, for F1 try both.
|
||||
TEST_F(ToolTipInfo, ResolveNamespaceAlias)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("A"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("B")});
|
||||
expected.setQdocMark(Utf8StringLiteral("B"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(144, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, QualificationForTemplateClassInClassInNamespace)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("N::Outer::Inner<int>"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("N::Outer::Inner"),
|
||||
Utf8StringLiteral("Outer::Inner"),
|
||||
Utf8StringLiteral("Inner")});
|
||||
expected.setQdocMark(Utf8StringLiteral("Inner"));
|
||||
expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace);
|
||||
expected.setSizeInBytes(Utf8StringLiteral("1"));
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(153, 16);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Function)
|
||||
{
|
||||
::ToolTipInfo expected(Utf8StringLiteral("void f()"));
|
||||
expected.setQdocIdCandidates({Utf8StringLiteral("f")});
|
||||
expected.setQdocMark(Utf8StringLiteral("f()"));
|
||||
expected.setQdocCategory(::ToolTipInfo::Function);
|
||||
|
||||
const ::ToolTipInfo actual = tooltip(165, 5);
|
||||
|
||||
ASSERT_THAT(actual, IsToolTip(expected));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Function_QualifiedName)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(166, 8);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("void R::f()"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Function_qdocIdCandidatesAreQualified)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(166, 8);
|
||||
|
||||
ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("R::f"),
|
||||
Utf8StringLiteral("f")));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(Function_HasParameterName))
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(167, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("void f(int param)"));
|
||||
}
|
||||
|
||||
// TODO: Implement with CXPrintingPolicy
|
||||
TEST_F(ToolTipInfo, DISABLED_Function_HasDefaultArgument)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(168, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("void z(int = 1)"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Function_qdocMarkHasNoParameterName)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(167, 5);
|
||||
|
||||
ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("f(int)"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, Function_qdocMarkHasNoDefaultArgument)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(168, 5);
|
||||
|
||||
ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("z(int)"));
|
||||
}
|
||||
|
||||
TEST_F(ToolTipInfo, AutoTypeBuiltin)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(176, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("int"));
|
||||
}
|
||||
|
||||
// TODO: Test for qdoc entries, too.
|
||||
TEST_F(ToolTipInfo, AutoTypeEnum)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(177, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("EnumType"));
|
||||
}
|
||||
|
||||
// TODO: Test for qdoc entries, too.
|
||||
TEST_F(ToolTipInfo, AutoTypeClassType)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(178, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("Bar"));
|
||||
}
|
||||
|
||||
// TODO: Test for qdoc entries, too.
|
||||
// TODO: Deduced template arguments work, too?!
|
||||
TEST_F(ToolTipInfo, AutoTypeClassTemplateType)
|
||||
{
|
||||
const ::ToolTipInfo actual = tooltip(179, 5);
|
||||
|
||||
ASSERT_THAT(actual.text(), Utf8StringLiteral("Zii<int>"));
|
||||
}
|
||||
|
||||
std::unique_ptr<Data> ToolTipInfo::d;
|
||||
|
||||
void ToolTipInfo::SetUpTestCase()
|
||||
{
|
||||
d.reset(new Data);
|
||||
}
|
||||
|
||||
void ToolTipInfo::TearDownTestCase()
|
||||
{
|
||||
d.reset();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
@@ -33,3 +33,9 @@
|
||||
#else
|
||||
# define DISABLED_ON_WINDOWS(x) x
|
||||
#endif
|
||||
|
||||
#ifdef IS_PRETTY_DECL_SUPPORTED
|
||||
# define DISABLED_WITHOUT_PRETTYDECL_PATCH(x) x
|
||||
#else
|
||||
# define DISABLED_WITHOUT_PRETTYDECL_PATCH(x) DISABLED_##x
|
||||
#endif
|
||||
|
180
tests/unit/unittest/data/tooltipinfo.cpp
Normal file
180
tests/unit/unittest/data/tooltipinfo.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
void f(int foo, const int *cfoo)
|
||||
{
|
||||
foo++;
|
||||
cfoo++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Foo { int member = 0; };
|
||||
int g(const Foo &foo)
|
||||
{
|
||||
return foo.member;
|
||||
const Foo bar;
|
||||
bar;
|
||||
}
|
||||
|
||||
struct Bar { virtual ~Bar(); int mem(){} virtual int virtualConstMem() const; };
|
||||
void h(const Foo &foo, Bar &bar)
|
||||
{
|
||||
g(foo);
|
||||
bar.mem();
|
||||
bar.virtualConstMem();
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void t(int foo) { (void)foo; }
|
||||
void c()
|
||||
{
|
||||
t<Foo>(3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief This is a crazy function.
|
||||
*/
|
||||
void documentedFunction();
|
||||
void d()
|
||||
{
|
||||
documentedFunction();
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum EnumType { V1, V2, Custom = V2 + 5 };
|
||||
EnumType e()
|
||||
{
|
||||
return EnumType::Custom;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> struct Baz { T member; };
|
||||
void t2(const Baz<int> &b) {
|
||||
Baz<int> baz; baz = b;
|
||||
}
|
||||
|
||||
#include "tooltipinfo.h"
|
||||
|
||||
|
||||
|
||||
#define MACRO_FROM_MAINFILE(x) x + 3
|
||||
void foo()
|
||||
{
|
||||
MACRO_FROM_MAINFILE(7);
|
||||
MACRO_FROM_HEADER(7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace N { struct Muu{}; }
|
||||
namespace G = N;
|
||||
void o()
|
||||
{
|
||||
using namespace N;
|
||||
Muu muu; (void)muu;
|
||||
}
|
||||
void n()
|
||||
{
|
||||
using namespace G;
|
||||
Muu muu; (void)muu;
|
||||
}
|
||||
void q()
|
||||
{
|
||||
using N::Muu;
|
||||
Muu muu; (void)muu;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Sizes
|
||||
{
|
||||
char memberChar1;
|
||||
char memberChar2;
|
||||
};
|
||||
enum class FancyEnumType { V1, V2 };
|
||||
union Union
|
||||
{
|
||||
char memberChar1;
|
||||
char memberChar2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace X {
|
||||
namespace Y {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T> struct Ptr {};
|
||||
struct Nuu {};
|
||||
|
||||
typedef Ptr<Nuu> PtrFromTypeDef;
|
||||
using PtrFromTypeAlias = Ptr<Nuu>;
|
||||
template<typename T> using PtrFromTemplateTypeAlias = Ptr<T>;
|
||||
|
||||
void y()
|
||||
{
|
||||
PtrFromTypeDef b; (void)b;
|
||||
PtrFromTypeAlias a; (void)a;
|
||||
PtrFromTemplateTypeAlias<Nuu> c; (void)c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T> struct Zii {};
|
||||
namespace U { template <typename T> struct Yii {}; }
|
||||
void mc()
|
||||
{
|
||||
using namespace U;
|
||||
Zii<int> zii; (void) zii;
|
||||
Yii<int> yii; (void) yii;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace A { struct X {}; }
|
||||
namespace B = A;
|
||||
void ab()
|
||||
{
|
||||
B::X x; (void)x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace N {
|
||||
struct Outer
|
||||
{
|
||||
template <typename T> struct Inner {};
|
||||
Inner<int> inner;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
void f();
|
||||
namespace R { void f(); }
|
||||
void f(int param);
|
||||
void z(int = 1);
|
||||
void user()
|
||||
{
|
||||
f();
|
||||
R::f();
|
||||
f(1);
|
||||
z();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void autoTypes()
|
||||
{
|
||||
auto a = 3; (void)a;
|
||||
auto b = EnumType::V1; (void)b;
|
||||
auto c = Bar(); (void)c;
|
||||
auto d = Zii<int>(); (void)d;
|
||||
}
|
3
tests/unit/unittest/data/tooltipinfo.h
Normal file
3
tests/unit/unittest/data/tooltipinfo.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#define MACRO_FROM_HEADER(x) x + \
|
||||
x + \
|
||||
x
|
@@ -38,4 +38,5 @@ public:
|
||||
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &) override {}
|
||||
void references(const ClangBackEnd::ReferencesMessage &) override {}
|
||||
void followSymbol(const ClangBackEnd::FollowSymbolMessage &) override {}
|
||||
void tooltip(const ClangBackEnd::ToolTipMessage &) override {}
|
||||
};
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <sourcelocationentry.h>
|
||||
#include <sourcelocationscontainer.h>
|
||||
#include <tokeninfos.h>
|
||||
#include <tooltipinfo.h>
|
||||
|
||||
#include <cpptools/usages.h>
|
||||
|
||||
@@ -269,6 +270,17 @@ std::ostream &operator<<(std::ostream &os, const ReferencesMessage &message)
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ToolTipMessage &message)
|
||||
{
|
||||
os << "("
|
||||
<< message.fileContainer() << ", "
|
||||
<< message.ticketNumber() << ", "
|
||||
<< message.toolTipInfo() << ", "
|
||||
<< ")";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const EchoMessage &/*message*/)
|
||||
{
|
||||
return os << "()";
|
||||
@@ -385,7 +397,8 @@ std::ostream &operator<<(std::ostream &os, const FileContainer &container)
|
||||
<< container.filePath() << ", "
|
||||
<< container.projectPartId() << ", "
|
||||
<< container.fileArguments() << ", "
|
||||
<< container.documentRevision();
|
||||
<< container.documentRevision() << ", "
|
||||
<< container.textCodecName();
|
||||
|
||||
if (container.hasUnsavedFileContent())
|
||||
os << ", "
|
||||
@@ -552,6 +565,37 @@ std::ostream &operator<<(std::ostream &os, const RequestReferencesMessage &messa
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const RequestToolTipMessage &message)
|
||||
{
|
||||
out << "("
|
||||
<< message.fileContainer() << ", "
|
||||
<< message.ticketNumber() << ", "
|
||||
<< message.line() << ", "
|
||||
<< message.column() << ", "
|
||||
<< ")";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ToolTipInfo::QdocCategory category)
|
||||
{
|
||||
return os << qdocCategoryToString(category);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const ToolTipInfo &info)
|
||||
{
|
||||
out << "("
|
||||
<< info.m_text << ", "
|
||||
<< info.m_briefComment << ", "
|
||||
<< info.m_qdocIdCandidates << ", "
|
||||
<< info.m_qdocMark << ", "
|
||||
<< info.m_qdocCategory
|
||||
<< info.m_sizeInBytes << ", "
|
||||
<< ")";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const RequestSourceLocationsForRenamingMessage &message)
|
||||
{
|
||||
|
||||
|
@@ -73,6 +73,7 @@ class CodeCompletedMessage;
|
||||
class EchoMessage;
|
||||
class DocumentAnnotationsChangedMessage;
|
||||
class ReferencesMessage;
|
||||
class ToolTipMessage;
|
||||
class FollowSymbolMessage;
|
||||
class CompleteCodeMessage;
|
||||
class EndMessage;
|
||||
@@ -97,6 +98,7 @@ class RemovePchProjectPartsMessage;
|
||||
class RequestDocumentAnnotationsMessage;
|
||||
class RequestFollowSymbolMessage;
|
||||
class RequestReferencesMessage;
|
||||
class RequestToolTipMessage;
|
||||
class RequestSourceLocationsForRenamingMessage;
|
||||
class RequestSourceRangesAndDiagnosticsForQueryMessage;
|
||||
class RequestSourceRangesForQueryMessage;
|
||||
@@ -114,6 +116,7 @@ class UpdateVisibleTranslationUnitsMessage;
|
||||
class FilePath;
|
||||
class TokenInfo;
|
||||
class TokenInfos;
|
||||
class ToolTipInfo;
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry);
|
||||
std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths);
|
||||
@@ -127,6 +130,7 @@ std::ostream &operator<<(std::ostream &out, const CodeCompletedMessage &message)
|
||||
std::ostream &operator<<(std::ostream &out, const EchoMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const DocumentAnnotationsChangedMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const ReferencesMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const ToolTipMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const FollowSymbolMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const CompleteCodeMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const EndMessage &message);
|
||||
@@ -153,6 +157,8 @@ std::ostream &operator<<(std::ostream &out, const RemovePchProjectPartsMessage &
|
||||
std::ostream &operator<<(std::ostream &out, const RequestDocumentAnnotationsMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const RequestFollowSymbolMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const RequestReferencesMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const RequestToolTipMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const ToolTipInfo &info);
|
||||
std::ostream &operator<<(std::ostream &out, const RequestSourceLocationsForRenamingMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const RequestSourceRangesAndDiagnosticsForQueryMessage &message);
|
||||
std::ostream &operator<<(std::ostream &out, const RequestSourceRangesForQueryMessage &message);
|
||||
|
@@ -45,4 +45,6 @@ public:
|
||||
void(const ClangBackEnd::ReferencesMessage &message));
|
||||
MOCK_METHOD1(followSymbol,
|
||||
void(const ClangBackEnd::FollowSymbolMessage &message));
|
||||
MOCK_METHOD1(tooltip,
|
||||
void(const ClangBackEnd::ToolTipMessage &message));
|
||||
};
|
||||
|
@@ -55,6 +55,8 @@ public:
|
||||
void(const ClangBackEnd::RequestReferencesMessage &message));
|
||||
MOCK_METHOD1(requestFollowSymbol,
|
||||
void(const ClangBackEnd::RequestFollowSymbolMessage &message));
|
||||
MOCK_METHOD1(requestToolTip,
|
||||
void(const ClangBackEnd::RequestToolTipMessage &message));
|
||||
MOCK_METHOD1(updateVisibleTranslationUnits,
|
||||
void(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message));
|
||||
};
|
||||
|
@@ -118,6 +118,7 @@ SOURCES += \
|
||||
clangstring-test.cpp \
|
||||
clangsupportivetranslationunitinitializer-test.cpp \
|
||||
clangsuspenddocumentjob-test.cpp \
|
||||
clangtooltipinfo-test.cpp \
|
||||
clangtranslationunits-test.cpp \
|
||||
clangtranslationunit-test.cpp \
|
||||
clangupdatedocumentannotationsjob-test.cpp \
|
||||
|
@@ -203,4 +203,32 @@ TEST_F(UnsavedFile, HasCharacterForLastLineColumn)
|
||||
ASSERT_TRUE(unsavedFile.hasCharacterAt(1, 7, 't'));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, LineRangeForInvalidLines)
|
||||
{
|
||||
::UnsavedFile unsavedFile(filePath, fileContent);
|
||||
|
||||
ASSERT_THAT(unsavedFile.lineRange(2, 1), Utf8String());
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, LineRangeForSingleLine)
|
||||
{
|
||||
::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo"));
|
||||
|
||||
ASSERT_THAT(unsavedFile.lineRange(1, 1), Utf8StringLiteral("foo"));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, LineRangeForSingleLineInMultipleLines)
|
||||
{
|
||||
::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo\nbar\n\baz"));
|
||||
|
||||
ASSERT_THAT(unsavedFile.lineRange(2, 2), Utf8StringLiteral("bar"));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, LineRangeForTwoLines)
|
||||
{
|
||||
::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo\nbar\n\baz"));
|
||||
|
||||
ASSERT_THAT(unsavedFile.lineRange(2, 3), Utf8StringLiteral("bar\n\baz"));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Reference in New Issue
Block a user