From 79383202916a0b73301e012269a995aa9219e34d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 31 Jul 2020 16:50:03 +0200 Subject: [PATCH] TextEditor: Introduce shortcut for forcing a function hint proposal ... and support it in the ClangCodeModel. This allows users to get function signature(s) displayed regardless of where exactly the cursor is on the function call. Fixes: QTCREATORBUG-19394 Change-Id: I033e8774db93680bfc3ee52610b817e0ef8ccc76 Reviewed-by: David Schulz --- .../clangcompletionassistinterface.cpp | 4 ++-- .../clangcompletionassistinterface.h | 5 +++++ .../clangcompletionassistprocessor.cpp | 1 + .../clangcompletionassistprovider.cpp | 6 ++++-- .../clangcompletionassistprovider.h | 4 +++- .../clangcompletioncontextanalyzer.cpp | 16 +++++++++++++++- .../clangcompletioncontextanalyzer.h | 3 ++- .../clangcodemodel/clangmodelmanagersupport.cpp | 8 +++++++- .../clangcodemodel/clangmodelmanagersupport.h | 2 ++ src/plugins/cppeditor/cppeditordocument.cpp | 6 ++++++ src/plugins/cppeditor/cppeditordocument.h | 2 ++ src/plugins/cppeditor/cppeditorwidget.cpp | 7 +++++-- .../cpptools/cppbuiltinmodelmanagersupport.cpp | 6 ++++++ .../cpptools/cppbuiltinmodelmanagersupport.h | 1 + src/plugins/cpptools/cppmodelmanager.cpp | 5 +++++ src/plugins/cpptools/cppmodelmanager.h | 1 + src/plugins/cpptools/cppmodelmanagersupport.h | 1 + src/plugins/texteditor/codeassist/assistenums.h | 3 ++- .../texteditor/codeassist/codeassistant.cpp | 4 +++- src/plugins/texteditor/texteditorconstants.h | 1 + src/plugins/texteditor/texteditorplugin.cpp | 10 ++++++++++ .../clangcompletionassistinterface.h | 3 +++ .../clangcompletioncontextanalyzer-test.cpp | 1 + 23 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp b/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp index 5391f369e2a..5468fe3cb0b 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistinterface.cpp @@ -30,8 +30,7 @@ namespace ClangCodeModel { namespace Internal { -ClangCompletionAssistInterface::ClangCompletionAssistInterface( - BackendCommunicator &communicator, +ClangCompletionAssistInterface::ClangCompletionAssistInterface(BackendCommunicator &communicator, CompletionType type, const TextEditor::TextEditorWidget *textEditorWidget, int position, const QString &fileName, @@ -40,6 +39,7 @@ ClangCompletionAssistInterface::ClangCompletionAssistInterface( const CPlusPlus::LanguageFeatures &features) : AssistInterface(textEditorWidget->document(), position, fileName, reason) , m_communicator(communicator) + , m_type(type) , m_headerPaths(headerPaths) , m_languageFeatures(features) , m_textEditorWidget(textEditorWidget) diff --git a/src/plugins/clangcodemodel/clangcompletionassistinterface.h b/src/plugins/clangcodemodel/clangcompletionassistinterface.h index 728aeef7b26..fb797edbc04 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistinterface.h +++ b/src/plugins/clangcodemodel/clangcompletionassistinterface.h @@ -33,10 +33,13 @@ namespace ClangCodeModel { namespace Internal { +enum class CompletionType { FunctionHint, Other }; + class ClangCompletionAssistInterface: public TextEditor::AssistInterface { public: ClangCompletionAssistInterface(BackendCommunicator &communicator, + CompletionType type, const TextEditor::TextEditorWidget *textEditorWidget, int position, const QString &fileName, @@ -45,6 +48,7 @@ public: const CPlusPlus::LanguageFeatures &features); BackendCommunicator &communicator() const; + CompletionType type() const { return m_type; } bool objcEnabled() const; const ProjectExplorer::HeaderPaths &headerPaths() const; CPlusPlus::LanguageFeatures languageFeatures() const; @@ -54,6 +58,7 @@ public: private: BackendCommunicator &m_communicator; + const CompletionType m_type; QStringList m_options; ProjectExplorer::HeaderPaths m_headerPaths; CPlusPlus::LanguageFeatures m_languageFeatures; diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index 34298b43021..b7faeb99d31 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -347,6 +347,7 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() analyzer.functionNameStart()); break; } + case ClangCompletionContextAnalyzer::CompleteNone: default: break; } diff --git a/src/plugins/clangcodemodel/clangcompletionassistprovider.cpp b/src/plugins/clangcodemodel/clangcompletionassistprovider.cpp index 93d733dfbbd..c69d7ccb5ad 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprovider.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprovider.cpp @@ -43,8 +43,9 @@ namespace ClangCodeModel { namespace Internal { -ClangCompletionAssistProvider::ClangCompletionAssistProvider(BackendCommunicator &communicator) - : m_communicator(communicator) +ClangCompletionAssistProvider::ClangCompletionAssistProvider(BackendCommunicator &communicator, + CompletionType type) + : m_communicator(communicator), m_type(type) { } @@ -68,6 +69,7 @@ TextEditor::AssistInterface *ClangCompletionAssistProvider::createAssistInterfac const CppTools::ProjectPart::Ptr projectPart = projectPartForFileBasedOnProcessor(filePath); if (projectPart) { return new ClangCompletionAssistInterface(m_communicator, + m_type, textEditorWidget, position, filePath, diff --git a/src/plugins/clangcodemodel/clangcompletionassistprovider.h b/src/plugins/clangcodemodel/clangcompletionassistprovider.h index 12139b35d77..870c13d00d5 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprovider.h +++ b/src/plugins/clangcodemodel/clangcompletionassistprovider.h @@ -26,6 +26,7 @@ #pragma once #include "clangbackendcommunicator.h" +#include "clangcompletionassistinterface.h" #include @@ -39,7 +40,7 @@ class ClangCompletionAssistProvider : public CppTools::CppCompletionAssistProvid Q_OBJECT public: - ClangCompletionAssistProvider(BackendCommunicator &communicator); + ClangCompletionAssistProvider(BackendCommunicator &communicator, CompletionType type); IAssistProvider::RunType runType() const override; @@ -53,6 +54,7 @@ public: private: BackendCommunicator &m_communicator; + CompletionType m_type; }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp index 7217b905b07..060c5016949 100644 --- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp +++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp @@ -84,7 +84,8 @@ void ClangCompletionContextAnalyzer::analyze() m_positionEndOfExpression = activationSequenceContextProcessor.operatorStartPosition(); m_positionForProposal = activationSequenceContextProcessor.startOfNamePosition(); - const bool actionIsSet = handleNonFunctionCall(afterOperatorPosition); + const bool actionIsSet = m_interface->type() != CompletionType::FunctionHint + && handleNonFunctionCall(afterOperatorPosition); if (!actionIsSet) { handleCommaInFunctionCall(); handleFunctionCall(afterOperatorPosition); @@ -150,6 +151,19 @@ void ClangCompletionContextAnalyzer::handleCommaInFunctionCall() void ClangCompletionContextAnalyzer::handleFunctionCall(int afterOperatorPosition) { + if (m_interface->type() == CompletionType::FunctionHint) { + const int functionNameStart = startOfFunctionCall(afterOperatorPosition); + if (functionNameStart >= 0) { + m_addSnippets = functionNameStart == afterOperatorPosition; + setActionAndClangPosition(PassThroughToLibClangAfterLeftParen, + m_positionForProposal, + functionNameStart); + } else { + m_completionAction = CompleteNone; + } + return; + } + if (m_completionOperator == T_LPAREN || m_completionOperator == T_LBRACE) { ExpressionUnderCursor expressionUnderCursor(m_languageFeatures); QTextCursor textCursor(m_interface->textDocument()); diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h index 08574e50186..2f0e9423c07 100644 --- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h +++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.h @@ -51,7 +51,8 @@ public: CompleteIncludePath, CompletePreprocessorDirective, CompleteSignal, - CompleteSlot + CompleteSlot, + CompleteNone }; CompletionAction completionAction() const { return m_completionAction; } unsigned completionOperator() const { return m_completionOperator; } diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 9e56b54b914..cbd1e66d024 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -69,7 +69,8 @@ static CppTools::CppModelManager *cppModelManager() } ClangModelManagerSupport::ClangModelManagerSupport() - : m_completionAssistProvider(m_communicator) + : m_completionAssistProvider(m_communicator, CompletionType::Other) + , m_functionHintAssistProvider(m_communicator, CompletionType::FunctionHint) , m_followSymbol(new ClangFollowSymbol) , m_refactoringEngine(new RefactoringEngine) { @@ -119,6 +120,11 @@ CppTools::CppCompletionAssistProvider *ClangModelManagerSupport::completionAssis return &m_completionAssistProvider; } +CppTools::CppCompletionAssistProvider *ClangModelManagerSupport::functionHintAssistProvider() +{ + return &m_functionHintAssistProvider; +} + TextEditor::BaseHoverHandler *ClangModelManagerSupport::createHoverHandler() { return new Internal::ClangHoverHandler; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 58426a941d9..40348f850cf 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -63,6 +63,7 @@ public: ~ClangModelManagerSupport() override; CppTools::CppCompletionAssistProvider *completionAssistProvider() override; + CppTools::CppCompletionAssistProvider *functionHintAssistProvider() override; TextEditor::BaseHoverHandler *createHoverHandler() override; CppTools::BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) override; @@ -121,6 +122,7 @@ private: UiHeaderOnDiskManager m_uiHeaderOnDiskManager; BackendCommunicator m_communicator; ClangCompletionAssistProvider m_completionAssistProvider; + ClangCompletionAssistProvider m_functionHintAssistProvider; std::unique_ptr m_followSymbol; std::unique_ptr m_refactoringEngine; diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index bae58d49cc6..1de94133488 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -142,6 +142,11 @@ CppTools::CppCompletionAssistProvider *CppEditorDocument::completionAssistProvid return m_completionAssistProvider; } +CppTools::CppCompletionAssistProvider *CppEditorDocument::functionHintAssistProvider() const +{ + return m_functionHintAssistProvider; +} + TextEditor::IAssistProvider *CppEditorDocument::quickFixAssistProvider() const { return CppEditorPlugin::instance()->quickFixProvider(); @@ -195,6 +200,7 @@ void CppEditorDocument::onMimeTypeChanged() m_isObjCEnabled = (mt == QLatin1String(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE) || mt == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)); m_completionAssistProvider = mm()->completionAssistProvider(); + m_functionHintAssistProvider = mm()->functionHintAssistProvider(); initializeTimer(); } diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h index d8fc7094aa5..b7a0219e0a2 100644 --- a/src/plugins/cppeditor/cppeditordocument.h +++ b/src/plugins/cppeditor/cppeditordocument.h @@ -53,6 +53,7 @@ public: bool isObjCEnabled() const; CppTools::CppCompletionAssistProvider *completionAssistProvider() const override; + CppTools::CppCompletionAssistProvider *functionHintAssistProvider() const override; TextEditor::IAssistProvider *quickFixAssistProvider() const override; void recalculateSemanticInfoDetached(); @@ -128,6 +129,7 @@ private: QScopedPointer m_processor; CppTools::CppCompletionAssistProvider *m_completionAssistProvider = nullptr; + CppTools::CppCompletionAssistProvider *m_functionHintAssistProvider = nullptr; // (Un)Registration in CppModelManager QScopedPointer m_editorDocumentHandle; diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 8861cd63e90..ddc0a09630c 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -1017,8 +1017,11 @@ void CppEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo, AssistInterface *CppEditorWidget::createAssistInterface(AssistKind kind, AssistReason reason) const { - if (kind == Completion) { - if (CppCompletionAssistProvider *cap = cppEditorDocument()->completionAssistProvider()) { + if (kind == Completion || kind == FunctionHint) { + CppCompletionAssistProvider * const cap = kind == Completion + ? cppEditorDocument()->completionAssistProvider() + : cppEditorDocument()->functionHintAssistProvider(); + if (cap) { LanguageFeatures features = LanguageFeatures::defaultFeatures(); if (Document::Ptr doc = d->m_lastSemanticInfo.doc) features = doc->languageFeatures(); diff --git a/src/plugins/cpptools/cppbuiltinmodelmanagersupport.cpp b/src/plugins/cpptools/cppbuiltinmodelmanagersupport.cpp index 0fad49c15f2..deca8a64b4f 100644 --- a/src/plugins/cpptools/cppbuiltinmodelmanagersupport.cpp +++ b/src/plugins/cpptools/cppbuiltinmodelmanagersupport.cpp @@ -74,6 +74,12 @@ CppCompletionAssistProvider *BuiltinModelManagerSupport::completionAssistProvide return m_completionAssistProvider.data(); } + +CppCompletionAssistProvider *BuiltinModelManagerSupport::functionHintAssistProvider() +{ + return nullptr; +} + TextEditor::BaseHoverHandler *BuiltinModelManagerSupport::createHoverHandler() { return new CppHoverHandler; diff --git a/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h b/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h index 3e6587ce8a6..74efad9da6f 100644 --- a/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h +++ b/src/plugins/cpptools/cppbuiltinmodelmanagersupport.h @@ -41,6 +41,7 @@ public: ~BuiltinModelManagerSupport() override; CppCompletionAssistProvider *completionAssistProvider() final; + CppCompletionAssistProvider *functionHintAssistProvider() override; TextEditor::BaseHoverHandler *createHoverHandler() final; BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) final; diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index ce9fe475bb4..ae4083f350e 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -1442,6 +1442,11 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const return d->m_activeModelManagerSupport->completionAssistProvider(); } +CppCompletionAssistProvider *CppModelManager::functionHintAssistProvider() const +{ + return d->m_activeModelManagerSupport->functionHintAssistProvider(); +} + TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const { return d->m_activeModelManagerSupport->createHoverHandler(); diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 69a8ac6faff..292f333b8df 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -180,6 +180,7 @@ public: void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider); CppCompletionAssistProvider *completionAssistProvider() const; + CppCompletionAssistProvider *functionHintAssistProvider() const; BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) const; TextEditor::BaseHoverHandler *createHoverHandler() const; diff --git a/src/plugins/cpptools/cppmodelmanagersupport.h b/src/plugins/cpptools/cppmodelmanagersupport.h index 462060a5a93..ccf7ee83de6 100644 --- a/src/plugins/cpptools/cppmodelmanagersupport.h +++ b/src/plugins/cpptools/cppmodelmanagersupport.h @@ -54,6 +54,7 @@ public: virtual ~ModelManagerSupport() = 0; virtual CppCompletionAssistProvider *completionAssistProvider() = 0; + virtual CppCompletionAssistProvider *functionHintAssistProvider() = 0; virtual TextEditor::BaseHoverHandler *createHoverHandler() = 0; virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) = 0; diff --git a/src/plugins/texteditor/codeassist/assistenums.h b/src/plugins/texteditor/codeassist/assistenums.h index 2a5995526d4..1f375a43cf3 100644 --- a/src/plugins/texteditor/codeassist/assistenums.h +++ b/src/plugins/texteditor/codeassist/assistenums.h @@ -31,7 +31,8 @@ enum AssistKind { Completion, QuickFix, - FollowSymbol + FollowSymbol, + FunctionHint }; enum AssistReason diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index ce90f64b482..f3fa3daafa5 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -180,7 +180,7 @@ void CodeAssistantPrivate::process() } startAutomaticProposalTimer(); - } else { + } else if (m_assistKind != FunctionHint){ m_assistKind = TextEditor::Completion; } } @@ -204,6 +204,8 @@ void CodeAssistantPrivate::requestProposal(AssistReason reason, if (!provider) { if (kind == Completion) provider = m_editorWidget->textDocument()->completionAssistProvider(); + else if (kind == FunctionHint) + provider = m_editorWidget->textDocument()->functionHintAssistProvider(); else provider = m_editorWidget->textDocument()->quickFixAssistProvider(); diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index 038c0913a52..740c687d3ee 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -124,6 +124,7 @@ const char G_COPYPASTE[] = "TextEditor.CopyPasteGroup"; const char G_SELECT[] = "TextEditor.SelectGroup"; const char G_BOM[] = "TextEditor.BomGroup"; const char COMPLETE_THIS[] = "TextEditor.CompleteThis"; +const char FUNCTION_HINT[] = "TextEditor.FunctionHint"; const char QUICKFIX_THIS[] = "TextEditor.QuickFix"; const char SHOWCONTEXTMENU[] = "TextEditor.ShowContextMenu"; const char CREATE_SCRATCH_BUFFER[] = "TextEditor.CreateScratchBuffer"; diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index 392a5062b63..6c614a36b33 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -131,6 +131,16 @@ bool TextEditorPlugin::initialize(const QStringList &arguments, QString *errorMe }); Utils::FancyLineEdit::setCompletionShortcut(command->keySequence()); + // Add shortcut for invoking function hint completion + QAction *functionHintAction = new QAction(tr("Display Function Hint"), this); + command = ActionManager::registerAction(functionHintAction, Constants::FUNCTION_HINT, context); + command->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Meta+Shift+D") + : tr("Ctrl+Shift+D"))); + connect(functionHintAction, &QAction::triggered, []() { + if (BaseTextEditor *editor = BaseTextEditor::currentTextEditor()) + editor->editorWidget()->invokeAssist(FunctionHint); + }); + // Add shortcut for invoking quick fix options QAction *quickFixAction = new QAction(tr("Trigger Refactoring Action"), this); Command *quickFixCommand = ActionManager::registerAction(quickFixAction, Constants::QUICKFIX_THIS, context); diff --git a/tests/unit/mockup/clangcodemodel/clangcompletionassistinterface.h b/tests/unit/mockup/clangcodemodel/clangcompletionassistinterface.h index 9596a19e133..9597506734f 100644 --- a/tests/unit/mockup/clangcodemodel/clangcompletionassistinterface.h +++ b/tests/unit/mockup/clangcodemodel/clangcompletionassistinterface.h @@ -32,6 +32,8 @@ namespace ClangCodeModel { namespace Internal { +enum class CompletionType { FunctionHint, Other }; + class ClangCompletionAssistInterface: public TextEditor::AssistInterface { public: @@ -41,6 +43,7 @@ public: languageFeatures_(CPlusPlus::LanguageFeatures::defaultFeatures()) {} + CompletionType type() const { return CompletionType::Other; } CPlusPlus::LanguageFeatures languageFeatures() const { return languageFeatures_; } private: diff --git a/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp b/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp index 324e9b3a7ea..b1ac930295c 100644 --- a/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp +++ b/tests/unit/unittest/clangcompletioncontextanalyzer-test.cpp @@ -48,6 +48,7 @@ void PrintTo(const ClangCompletionContextAnalyzer::CompletionAction &completionA case CCA::CompletePreprocessorDirective: *os << "CompletePreprocessorDirective"; break; case CCA::CompleteSignal: *os << "CompleteSignal"; break; case CCA::CompleteSlot: *os << "CompleteSlot"; break; + case CCA::CompleteNone: *os << "CompleteNone"; break; } }