ClangCodeModel: Show value in tool tips, if possible

When hovering over a constant expression, it's probably helpful
to show that value to the user.
Requires clang 11 to fully work. For now, it only shows the value for
variable initializations.

Fixes: QTCREATORBUG-23967
Change-Id: I6b844231bac50993c2fa2fa82c552ad9cef590df
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Christian Kandeler
2020-05-18 17:40:19 +02:00
parent 227904d4a6
commit 949bb0e67b
7 changed files with 61 additions and 1 deletions

View File

@@ -28,6 +28,8 @@
#include <utf8string.h> #include <utf8string.h>
#include <utf8stringvector.h> #include <utf8stringvector.h>
#include <QVariant>
namespace ClangBackEnd { namespace ClangBackEnd {
class ToolTipInfo class ToolTipInfo
@@ -54,6 +56,7 @@ public:
out << message.qdocIdCandidates; out << message.qdocIdCandidates;
out << message.qdocMark; out << message.qdocMark;
out << static_cast<quint8>(message.qdocCategory); out << static_cast<quint8>(message.qdocCategory);
out << message.value;
out << message.sizeInBytes; out << message.sizeInBytes;
return out; return out;
@@ -68,6 +71,7 @@ public:
in >> message.qdocIdCandidates; in >> message.qdocIdCandidates;
in >> message.qdocMark; in >> message.qdocMark;
in >> qdocCategory; in >> qdocCategory;
in >> message.value;
in >> message.sizeInBytes; in >> message.sizeInBytes;
message.qdocCategory = static_cast<QdocCategory>(qdocCategory); message.qdocCategory = static_cast<QdocCategory>(qdocCategory);
@@ -82,6 +86,7 @@ public:
&& first.qdocIdCandidates == second.qdocIdCandidates && first.qdocIdCandidates == second.qdocIdCandidates
&& first.qdocMark == second.qdocMark && first.qdocMark == second.qdocMark
&& first.qdocCategory == second.qdocCategory && first.qdocCategory == second.qdocCategory
&& first.value == second.value
&& first.sizeInBytes == second.sizeInBytes; && first.sizeInBytes == second.sizeInBytes;
} }
@@ -92,6 +97,7 @@ public:
Utf8StringVector qdocIdCandidates; Utf8StringVector qdocIdCandidates;
Utf8String qdocMark; Utf8String qdocMark;
QdocCategory qdocCategory = Unknown; QdocCategory qdocCategory = Unknown;
QVariant value;
// For class definition and for class fields. // For class definition and for class fields.
Utf8String sizeInBytes; Utf8String sizeInBytes;

View File

@@ -339,7 +339,7 @@ static CppTools::ToolTipInfo toToolTipInfo(const ToolTipMessage &message)
info.qDocIdCandidates = toStringList(backendInfo.qdocIdCandidates); info.qDocIdCandidates = toStringList(backendInfo.qdocIdCandidates);
info.qDocMark = backendInfo.qdocMark; info.qDocMark = backendInfo.qdocMark;
info.qDocCategory = toHelpItemCategory(backendInfo.qdocCategory); info.qDocCategory = toHelpItemCategory(backendInfo.qdocCategory);
info.value = backendInfo.value;
info.sizeInBytes = backendInfo.sizeInBytes; info.sizeInBytes = backendInfo.sizeInBytes;
return info; return info;

View File

@@ -181,6 +181,22 @@ void ClangHoverHandler::processToolTipInfo(const CppTools::ToolTipInfo &info)
if (!info.sizeInBytes.isEmpty()) if (!info.sizeInBytes.isEmpty())
text.append("\n\n" + tr("%1 bytes").arg(info.sizeInBytes)); text.append("\n\n" + tr("%1 bytes").arg(info.sizeInBytes));
if (info.value.isValid()) {
text.append("\n\n" + tr("Value: "));
switch (info.value.type()) {
case static_cast<QVariant::Type>(QMetaType::LongLong):
text.append(QString::number(info.value.toLongLong()));
break;
case static_cast<QVariant::Type>(QMetaType::ULongLong):
text.append(QString::number(info.value.toULongLong()));
break;
case static_cast<QVariant::Type>(QMetaType::Double):
text.append(QString::number(info.value.toDouble()));
break;
default:
QTC_CHECK(false);
}
}
setToolTip(text); setToolTip(text);
m_reportPriority(priority()); m_reportPriority(priority());

View File

@@ -41,6 +41,8 @@
#include <QTextEdit> #include <QTextEdit>
#include <QVariant>
#include <functional> #include <functional>
namespace TextEditor { namespace TextEditor {
@@ -57,6 +59,7 @@ struct CPPTOOLS_EXPORT ToolTipInfo {
QStringList qDocIdCandidates; QStringList qDocIdCandidates;
QString qDocMark; QString qDocMark;
Core::HelpItem::Category qDocCategory; Core::HelpItem::Category qDocCategory;
QVariant value;
QString sizeInBytes; QString sizeInBytes;
}; };

View File

@@ -149,6 +149,28 @@ Utf8String sizeInBytes(const Cursor &cursor)
return Utf8String(); return Utf8String();
} }
QVariant value(const Cursor &cursor)
{
if (!clang_isDeclaration(cursor.cx().kind) && !clang_isExpression(cursor.cx().kind))
return {};
const CXEvalResult evalResult = clang_Cursor_Evaluate(cursor.cx());
QVariant v;
switch (clang_EvalResult_getKind(evalResult)) {
case CXEval_Int:
v = clang_EvalResult_isUnsignedInt(evalResult)
? QVariant::fromValue(clang_EvalResult_getAsUnsigned(evalResult))
: QVariant::fromValue(clang_EvalResult_getAsLongLong(evalResult));
break;
case CXEval_Float:
v = QVariant::fromValue(clang_EvalResult_getAsDouble(evalResult));
break;
default:
break;
}
clang_EvalResult_dispose(evalResult);
return v;
}
Cursor referencedCursor(const Cursor &cursor) Cursor referencedCursor(const Cursor &cursor)
{ {
// Query the referenced cursor directly instead of first testing with cursor.isReference(). // Query the referenced cursor directly instead of first testing with cursor.isReference().
@@ -503,6 +525,7 @@ ToolTipInfo ToolTipInfoCollector::collect(uint line, uint column) const
ToolTipInfo info; ToolTipInfo info;
info.text = text(cursor, referenced); info.text = text(cursor, referenced);
info.briefComment = referenced.briefComment(); info.briefComment = referenced.briefComment();
info.value = value(cursor);
{ {
ToolTipInfo qDocToolTipInfo = qDocInfo(referenced); ToolTipInfo qDocToolTipInfo = qDocInfo(referenced);

View File

@@ -385,6 +385,15 @@ TEST_F(ToolTipInfo, SizeForUnion)
ASSERT_THAT(actual.sizeInBytes, Utf8StringLiteral("1")); ASSERT_THAT(actual.sizeInBytes, Utf8StringLiteral("1"));
} }
TEST_F(ToolTipInfo, constexprValue)
{
// CLANG-UPGRADE-CHECK: Adapt the values below
ASSERT_THAT(tooltip(204, 12).value.toInt(), 4);
ASSERT_THAT(tooltip(204, 27).value.toInt(), 4); // 3 in clang 11
ASSERT_THAT(tooltip(204, 30).value.toInt(), 4);
ASSERT_THAT(tooltip(204, 32).value.toInt(), 4); // 1 in clang 11
}
TEST_F(ToolTipInfo, Namespace) TEST_F(ToolTipInfo, Namespace)
{ {
::ToolTipInfo expected(Utf8StringLiteral("X")); ::ToolTipInfo expected(Utf8StringLiteral("X"));

View File

@@ -199,3 +199,6 @@ Nuu **pointers(Nuu **p1)
{ {
return p1; return p1;
} }
static constexpr int calcValue() { return 1 + 2; }
const auto val = calcValue() + sizeof(char);