forked from qt-creator/qt-creator
CppEditor: Consider selection when requesting quickfixes
If the user has a token selected, prefer that to the actual cursor position. Fixes: QTCREATORBUG-27886 Change-Id: Ib32e24676510bff42292fe23e4962720fcbac4ed Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
10
src/libs/3rdparty/cplusplus/TranslationUnit.cpp
vendored
10
src/libs/3rdparty/cplusplus/TranslationUnit.cpp
vendored
@@ -26,6 +26,9 @@
|
|||||||
#include "AST.h"
|
#include "AST.h"
|
||||||
#include "Literals.h"
|
#include "Literals.h"
|
||||||
#include "DiagnosticClient.h"
|
#include "DiagnosticClient.h"
|
||||||
|
|
||||||
|
#include <utils/textutils.h>
|
||||||
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
@@ -382,6 +385,13 @@ void TranslationUnit::getTokenPosition(int index,
|
|||||||
const StringLiteral **fileName) const
|
const StringLiteral **fileName) const
|
||||||
{ return getPosition(tokenAt(index).utf16charsBegin(), line, column, fileName); }
|
{ return getPosition(tokenAt(index).utf16charsBegin(), line, column, fileName); }
|
||||||
|
|
||||||
|
int TranslationUnit::getTokenPositionInDocument(int index, const QTextDocument *doc) const
|
||||||
|
{
|
||||||
|
int line, column;
|
||||||
|
getTokenPosition(index, &line, &column);
|
||||||
|
return Utils::Text::positionInText(doc, line, column);
|
||||||
|
}
|
||||||
|
|
||||||
void TranslationUnit::getTokenStartPosition(int index, int *line,
|
void TranslationUnit::getTokenStartPosition(int index, int *line,
|
||||||
int *column,
|
int *column,
|
||||||
const StringLiteral **fileName) const
|
const StringLiteral **fileName) const
|
||||||
|
@@ -28,6 +28,10 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QTextDocument;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
|
|
||||||
class CPLUSPLUS_EXPORT TranslationUnit
|
class CPLUSPLUS_EXPORT TranslationUnit
|
||||||
@@ -124,6 +128,8 @@ public:
|
|||||||
int *column = nullptr,
|
int *column = nullptr,
|
||||||
const StringLiteral **fileName = nullptr) const;
|
const StringLiteral **fileName = nullptr) const;
|
||||||
|
|
||||||
|
int getTokenPositionInDocument(int index, const QTextDocument *doc) const;
|
||||||
|
|
||||||
void pushLineOffset(int offset);
|
void pushLineOffset(int offset);
|
||||||
void pushPreprocessorLine(int utf16charOffset,
|
void pushPreprocessorLine(int utf16charOffset,
|
||||||
int line,
|
int line,
|
||||||
|
@@ -86,7 +86,7 @@ CppQuickFixInterface::CppQuickFixInterface(CppEditorWidget *editor, AssistReason
|
|||||||
QTC_CHECK(m_semanticInfo.doc->translationUnit());
|
QTC_CHECK(m_semanticInfo.doc->translationUnit());
|
||||||
QTC_CHECK(m_semanticInfo.doc->translationUnit()->ast());
|
QTC_CHECK(m_semanticInfo.doc->translationUnit()->ast());
|
||||||
ASTPath astPath(m_semanticInfo.doc);
|
ASTPath astPath(m_semanticInfo.doc);
|
||||||
m_path = astPath(editor->textCursor());
|
m_path = astPath(adjustedCursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<AST *> &CppQuickFixInterface::path() const
|
const QList<AST *> &CppQuickFixInterface::path() const
|
||||||
@@ -129,6 +129,50 @@ bool CppQuickFixInterface::isCursorOn(const AST *ast) const
|
|||||||
return currentFile()->isCursorOn(ast);
|
return currentFile()->isCursorOn(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some users like to select identifiers and expect the quickfix to apply to the selection.
|
||||||
|
// However, as the cursor position is at the end of the selection, it can happen that
|
||||||
|
// the quickfix is applied to the following token instead; see e.g. QTCREATORBUG-27886.
|
||||||
|
// We try to detect this condition: If there is a selection *and* this selection
|
||||||
|
// corresponds to a C++ token, we move the cursor to that token's position.
|
||||||
|
QTextCursor CppQuickFixInterface::adjustedCursor()
|
||||||
|
{
|
||||||
|
QTextCursor cursor = this->cursor();
|
||||||
|
if (!cursor.hasSelection())
|
||||||
|
return cursor;
|
||||||
|
|
||||||
|
const TranslationUnit * const tu = m_semanticInfo.doc->translationUnit();
|
||||||
|
const int selStart = cursor.selectionStart();
|
||||||
|
const int selEnd = cursor.selectionEnd();
|
||||||
|
const QTextDocument * const doc = m_editor->textDocument()->document();
|
||||||
|
|
||||||
|
// Binary search for matching token.
|
||||||
|
for (int l = 0, u = tu->tokenCount() - 1; l <= u; ) {
|
||||||
|
const int i = (l + u) / 2;
|
||||||
|
const int tokenPos = tu->getTokenPositionInDocument(i, doc);
|
||||||
|
if (selStart < tokenPos) {
|
||||||
|
u = i - 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (selStart > tokenPos) {
|
||||||
|
l = i + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selection does not end at token end.
|
||||||
|
if (tokenPos + tu->tokenAt(i).utf16chars() != selEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
cursor.setPosition(selStart);
|
||||||
|
|
||||||
|
// Try not to have the cursor "at the edge", in order to prevent potential ambiguities.
|
||||||
|
if (selEnd - selStart > 1)
|
||||||
|
cursor.setPosition(cursor.position() + 1);
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
QuickFixOperations quickFixOperations(const TextEditor::AssistInterface *interface)
|
QuickFixOperations quickFixOperations(const TextEditor::AssistInterface *interface)
|
||||||
{
|
{
|
||||||
const auto cppInterface = dynamic_cast<const CppQuickFixInterface *>(interface);
|
const auto cppInterface = dynamic_cast<const CppQuickFixInterface *>(interface);
|
||||||
|
@@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <cplusplus/LookupContext.h>
|
#include <cplusplus/LookupContext.h>
|
||||||
|
|
||||||
|
|
||||||
namespace CppEditor {
|
namespace CppEditor {
|
||||||
class CppEditorWidget;
|
class CppEditorWidget;
|
||||||
class CppRefactoringFile;
|
class CppRefactoringFile;
|
||||||
@@ -59,6 +58,8 @@ public:
|
|||||||
bool isBaseObject() const override { return false; }
|
bool isBaseObject() const override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QTextCursor adjustedCursor();
|
||||||
|
|
||||||
CppEditorWidget *m_editor;
|
CppEditorWidget *m_editor;
|
||||||
SemanticInfo m_semanticInfo;
|
SemanticInfo m_semanticInfo;
|
||||||
CPlusPlus::Snapshot m_snapshot;
|
CPlusPlus::Snapshot m_snapshot;
|
||||||
|
Reference in New Issue
Block a user