diff options
Diffstat (limited to 'src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp')
-rw-r--r-- | src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp b/src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp new file mode 100644 index 0000000000..834abaed8a --- /dev/null +++ b/src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp @@ -0,0 +1,162 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "cppquickfixassistant.h" + +#include "../cppeditorwidget.h" +#include "../cppmodelmanager.h" +#include "../cpprefactoringchanges.h" +#include "cppquickfix.h" + +#include <texteditor/codeassist/genericproposal.h> +#include <texteditor/codeassist/iassistprocessor.h> +#include <texteditor/textdocument.h> + +#include <cplusplus/ASTPath.h> + +#include <utils/algorithm.h> +#include <utils/qtcassert.h> + +using namespace CPlusPlus; +using namespace TextEditor; + +namespace CppEditor::Internal { + +// CppQuickFixAssistProvider + +class CppQuickFixAssistProvider final : public IAssistProvider +{ +public: + class CppQuickFixAssistProcessor final : public IAssistProcessor + { + IAssistProposal *perform() final + { + return GenericProposal::createProposal(interface(), quickFixOperations(interface())); + } + }; + + TextEditor::IAssistProcessor *createProcessor(const TextEditor::AssistInterface *) const final + { + return new CppQuickFixAssistProcessor; + } +}; + +IAssistProvider &cppQuickFixAssistProvider() +{ + static CppQuickFixAssistProvider theCppQuickFixAssistProvider; + return theCppQuickFixAssistProvider; +} + +// CppQuickFixAssistInterface + +CppQuickFixInterface::CppQuickFixInterface(CppEditorWidget *editor, AssistReason reason) + : AssistInterface(editor->textCursor(), editor->textDocument()->filePath(), reason) + , m_editor(editor) + , m_semanticInfo(editor->semanticInfo()) + , m_snapshot(CppModelManager::snapshot()) + , m_currentFile(CppRefactoringChanges::file(editor, m_semanticInfo.doc)) + , m_context(m_semanticInfo.doc, m_snapshot) +{ + QTC_CHECK(m_semanticInfo.doc); + QTC_CHECK(m_semanticInfo.doc->translationUnit()); + QTC_CHECK(m_semanticInfo.doc->translationUnit()->ast()); + ASTPath astPath(m_semanticInfo.doc); + m_path = astPath(adjustedCursor()); +} + +const QList<AST *> &CppQuickFixInterface::path() const +{ + return m_path; +} + +Snapshot CppQuickFixInterface::snapshot() const +{ + return m_snapshot; +} + +SemanticInfo CppQuickFixInterface::semanticInfo() const +{ + return m_semanticInfo; +} + +const LookupContext &CppQuickFixInterface::context() const +{ + return m_context; +} + +CppEditorWidget *CppQuickFixInterface::editor() const +{ + return m_editor; +} + +CppRefactoringFilePtr CppQuickFixInterface::currentFile() const +{ + return m_currentFile; +} + +bool CppQuickFixInterface::isCursorOn(unsigned tokenIndex) const +{ + return currentFile()->isCursorOn(tokenIndex); +} + +bool CppQuickFixInterface::isCursorOn(const AST *ast) const +{ + 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) +{ + const auto cppInterface = dynamic_cast<const CppQuickFixInterface *>(interface); + if (!cppInterface) + return {}; + QuickFixOperations quickFixes; + for (CppQuickFixFactory *factory : CppQuickFixFactory::cppQuickFixFactories()) + factory->match(*cppInterface, quickFixes); + return quickFixes; +} + +} // namespace CppEditor::Internal |