forked from qt-creator/qt-creator
Debugger: Use line information to find matching scopes for tooltips
More robust to variations in tool chains than function names. (e.g. GDB reports 'foo' and LLDB 'foo()') Change-Id: I1e5a3273b571658b4dd4200c9b3a0e9542a16015 Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -726,7 +726,7 @@ public:
|
|||||||
void positionShow(const TextEditorWidget *editorWidget);
|
void positionShow(const TextEditorWidget *editorWidget);
|
||||||
|
|
||||||
void handleItemIsExpanded(const QModelIndex &sourceIdx);
|
void handleItemIsExpanded(const QModelIndex &sourceIdx);
|
||||||
void updateTooltip(const QString &frameFile, const QString &frameFunction);
|
void updateTooltip(const StackFrame &frame);
|
||||||
|
|
||||||
void setState(State newState);
|
void setState(State newState);
|
||||||
|
|
||||||
@@ -769,7 +769,7 @@ void DebuggerToolTipHolder::handleItemIsExpanded(const QModelIndex &sourceIdx)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
DebuggerToolTipContext::DebuggerToolTipContext()
|
DebuggerToolTipContext::DebuggerToolTipContext()
|
||||||
: position(0), line(0), column(0)
|
: position(0), line(0), column(0), scopeFromLine(0), scopeToLine(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,25 +780,26 @@ static bool filesMatch(const QString &file1, const QString &file2)
|
|||||||
return f1.canonicalFilePath() == f2.canonicalFilePath();
|
return f1.canonicalFilePath() == f2.canonicalFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuggerToolTipContext::matchesFrame(const QString &frameFile, const QString &frameFunction) const
|
bool DebuggerToolTipContext::matchesFrame(const StackFrame &frame) const
|
||||||
{
|
{
|
||||||
return (fileName.isEmpty() || frameFile.isEmpty() || filesMatch(fileName, frameFile))
|
return (fileName.isEmpty() || frame.file.isEmpty() || filesMatch(fileName, frame.file))
|
||||||
&& (function.isEmpty() || frameFunction.isEmpty() || function == frameFunction);
|
//&& (function.isEmpty() || frame.function.isEmpty() || function == frame.function);
|
||||||
|
&& (frame.line <= 0 || (scopeFromLine <= frame.line && frame.line <= scopeToLine));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuggerToolTipContext::isSame(const DebuggerToolTipContext &other) const
|
bool DebuggerToolTipContext::isSame(const DebuggerToolTipContext &other) const
|
||||||
{
|
{
|
||||||
return filesMatch(fileName, other.fileName)
|
return filesMatch(fileName, other.fileName)
|
||||||
&& function == other.function
|
&& scopeFromLine == other.scopeFromLine
|
||||||
|
&& scopeToLine == other.scopeToLine
|
||||||
&& iname == other.iname;
|
&& iname == other.iname;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug d, const DebuggerToolTipContext &c)
|
QDebug operator<<(QDebug d, const DebuggerToolTipContext &c)
|
||||||
{
|
{
|
||||||
QDebug nsp = d.nospace();
|
QDebug nsp = d.nospace();
|
||||||
nsp << c.fileName << '@' << c.line << ',' << c.column << " (" << c.position << ')' << "INAME: " << c.iname << " EXP: " << c.expression;
|
nsp << c.fileName << '@' << c.line << ',' << c.column << " (" << c.position << ')'
|
||||||
if (!c.function.isEmpty())
|
<< "INAME: " << c.iname << " EXP: " << c.expression << " FUNCTION: " << c.function;
|
||||||
nsp << ' ' << c.function << "()";
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,9 +869,9 @@ DebuggerToolTipHolder::~DebuggerToolTipHolder()
|
|||||||
delete widget; widget.clear();
|
delete widget; widget.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerToolTipHolder::updateTooltip(const QString &frameFile, const QString &frameFunction)
|
void DebuggerToolTipHolder::updateTooltip(const StackFrame &frame)
|
||||||
{
|
{
|
||||||
const bool sameFrame = context.matchesFrame(frameFile, frameFunction);
|
const bool sameFrame = context.matchesFrame(frame);
|
||||||
DEBUG("UPDATE TOOLTIP: STATE " << state << context.iname
|
DEBUG("UPDATE TOOLTIP: STATE " << state << context.iname
|
||||||
<< "PINNED: " << widget->isPinned << "SAME FRAME: " << sameFrame);
|
<< "PINNED: " << widget->isPinned << "SAME FRAME: " << sameFrame);
|
||||||
|
|
||||||
@@ -1197,18 +1198,9 @@ void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine)
|
|||||||
|
|
||||||
// Stack frame changed: All tooltips of that file acquire the engine,
|
// Stack frame changed: All tooltips of that file acquire the engine,
|
||||||
// all others release (arguable, this could be more precise?)
|
// all others release (arguable, this could be more precise?)
|
||||||
QString fileName;
|
StackFrame frame = engine->stackHandler()->currentFrame();
|
||||||
QString function;
|
|
||||||
const int index = engine->stackHandler()->currentIndex();
|
|
||||||
if (index >= 0) {
|
|
||||||
const StackFrame frame = engine->stackHandler()->currentFrame();
|
|
||||||
if (frame.usable) {
|
|
||||||
fileName = frame.file;
|
|
||||||
function = frame.function;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips)
|
||||||
tooltip->updateTooltip(fileName, function);
|
tooltip->updateTooltip(frame);
|
||||||
slotUpdateVisibleToolTips(); // Move tooltip when stepping in same file.
|
slotUpdateVisibleToolTips(); // Move tooltip when stepping in same file.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,7 +1313,8 @@ static void slotTooltipOverrideRequested
|
|||||||
context.position = pos;
|
context.position = pos;
|
||||||
context.mousePosition = point;
|
context.mousePosition = point;
|
||||||
editorWidget->convertPosition(pos, &context.line, &context.column);
|
editorWidget->convertPosition(pos, &context.line, &context.column);
|
||||||
QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column, &context.function);
|
QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column,
|
||||||
|
&context.function, &context.scopeFromLine, &context.scopeToLine);
|
||||||
context.expression = fixCppExpression(raw);
|
context.expression = fixCppExpression(raw);
|
||||||
|
|
||||||
if (context.expression.isEmpty()) {
|
if (context.expression.isEmpty()) {
|
||||||
@@ -1426,9 +1419,9 @@ DebuggerToolTipContexts DebuggerToolTipManager::pendingTooltips(DebuggerEngine *
|
|||||||
StackFrame frame = engine->stackHandler()->currentFrame();
|
StackFrame frame = engine->stackHandler()->currentFrame();
|
||||||
DebuggerToolTipContexts rc;
|
DebuggerToolTipContexts rc;
|
||||||
foreach (DebuggerToolTipHolder *tooltip, m_tooltips) {
|
foreach (DebuggerToolTipHolder *tooltip, m_tooltips) {
|
||||||
if (tooltip->context.iname.startsWith("tooltip")
|
const DebuggerToolTipContext &context = tooltip->context;
|
||||||
&& tooltip->context.matchesFrame(frame.file, frame.function))
|
if (context.iname.startsWith("tooltip") && context.matchesFrame(frame))
|
||||||
rc.push_back(tooltip->context);
|
rc.push_back(context);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,19 +47,23 @@ class DebuggerEngine;
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class StackFrame;
|
||||||
|
|
||||||
class DebuggerToolTipContext
|
class DebuggerToolTipContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DebuggerToolTipContext();
|
DebuggerToolTipContext();
|
||||||
bool isValid() const { return !expression.isEmpty(); }
|
bool isValid() const { return !expression.isEmpty(); }
|
||||||
bool matchesFrame(const QString &frameFile, const QString &frameFunction) const;
|
bool matchesFrame(const StackFrame &frame) const;
|
||||||
bool isSame(const DebuggerToolTipContext &other) const;
|
bool isSame(const DebuggerToolTipContext &other) const;
|
||||||
|
|
||||||
QString fileName;
|
QString fileName;
|
||||||
int position;
|
int position;
|
||||||
int line;
|
int line;
|
||||||
int column;
|
int column;
|
||||||
QString function; //!< Optional function. This must be set by the engine as it is language-specific.
|
int scopeFromLine;
|
||||||
|
int scopeToLine;
|
||||||
|
QString function; //!< Optional, informational only.
|
||||||
QString engineType;
|
QString engineType;
|
||||||
QDate creationDate;
|
QDate creationDate;
|
||||||
|
|
||||||
|
|||||||
@@ -269,11 +269,7 @@ bool isCppEditor(TextEditorWidget *editorWidget)
|
|||||||
|
|
||||||
QString cppFunctionAt(const QString &fileName, int line, int column)
|
QString cppFunctionAt(const QString &fileName, int line, int column)
|
||||||
{
|
{
|
||||||
CppModelManager *modelManager = CppModelManager::instance();
|
const Snapshot snapshot = CppModelManager::instance()->snapshot();
|
||||||
if (!modelManager)
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
const Snapshot snapshot = modelManager->snapshot();
|
|
||||||
if (const Document::Ptr document = snapshot.document(fileName))
|
if (const Document::Ptr document = snapshot.document(fileName))
|
||||||
return document->functionAt(line, column);
|
return document->functionAt(line, column);
|
||||||
|
|
||||||
@@ -283,7 +279,8 @@ QString cppFunctionAt(const QString &fileName, int line, int column)
|
|||||||
|
|
||||||
// Return the Cpp expression, and, if desired, the function
|
// Return the Cpp expression, and, if desired, the function
|
||||||
QString cppExpressionAt(TextEditorWidget *editorWidget, int pos,
|
QString cppExpressionAt(TextEditorWidget *editorWidget, int pos,
|
||||||
int *line, int *column, QString *function /* = 0 */)
|
int *line, int *column, QString *function,
|
||||||
|
int *scopeFromLine, int *scopeToLine)
|
||||||
{
|
{
|
||||||
*line = *column = 0;
|
*line = *column = 0;
|
||||||
if (function)
|
if (function)
|
||||||
@@ -291,8 +288,7 @@ QString cppExpressionAt(TextEditorWidget *editorWidget, int pos,
|
|||||||
|
|
||||||
QTextCursor tc = editorWidget->textCursor();
|
QTextCursor tc = editorWidget->textCursor();
|
||||||
QString expr = tc.selectedText();
|
QString expr = tc.selectedText();
|
||||||
CppModelManager *modelManager = CppModelManager::instance();
|
if (expr.isEmpty()) {
|
||||||
if (expr.isEmpty() && modelManager) {
|
|
||||||
tc.setPosition(pos);
|
tc.setPosition(pos);
|
||||||
const QChar ch = editorWidget->characterAt(pos);
|
const QChar ch = editorWidget->characterAt(pos);
|
||||||
if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
|
if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
|
||||||
@@ -308,8 +304,15 @@ QString cppExpressionAt(TextEditorWidget *editorWidget, int pos,
|
|||||||
*line = tc.blockNumber();
|
*line = tc.blockNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (function && !expr.isEmpty())
|
if (!expr.isEmpty()) {
|
||||||
*function = cppFunctionAt(editorWidget->textDocument()->filePath(), *line, *column);
|
QString fileName = editorWidget->textDocument()->filePath();
|
||||||
|
const Snapshot snapshot = CppModelManager::instance()->snapshot();
|
||||||
|
if (const Document::Ptr document = snapshot.document(fileName)) {
|
||||||
|
QString func = document->functionAt(*line, *column, scopeFromLine, scopeToLine);
|
||||||
|
if (function)
|
||||||
|
*function = func;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ namespace Internal {
|
|||||||
// Editor tooltip support
|
// Editor tooltip support
|
||||||
bool isCppEditor(TextEditor::TextEditorWidget *editorWidget);
|
bool isCppEditor(TextEditor::TextEditorWidget *editorWidget);
|
||||||
QString cppExpressionAt(TextEditor::TextEditorWidget *editorWidget, int pos,
|
QString cppExpressionAt(TextEditor::TextEditorWidget *editorWidget, int pos,
|
||||||
int *line, int *column, QString *function = 0);
|
int *line, int *column, QString *function = 0,
|
||||||
|
int *scopeFromLine = 0, int *scopeToLine = 0);
|
||||||
QString fixCppExpression(const QString &exp);
|
QString fixCppExpression(const QString &exp);
|
||||||
QString cppFunctionAt(const QString &fileName, int line, int column = 0);
|
QString cppFunctionAt(const QString &fileName, int line, int column = 0);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user