aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp')
-rw-r--r--src/plugins/cppeditor/quickfixes/cppquickfixassistant.cpp162
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