forked from qt-creator/qt-creator
CppEditor: refactor FollowSymbol
Create an interface to get the ability to use another FollowSymbol implementation Change-Id: I5802f62523ff3ee47b8a14e487adf43edcb6c9b1 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
@@ -23,6 +23,7 @@ SOURCES += \
|
|||||||
clangeditordocumentprocessor.cpp \
|
clangeditordocumentprocessor.cpp \
|
||||||
clangfixitoperation.cpp \
|
clangfixitoperation.cpp \
|
||||||
clangfixitoperationsextractor.cpp \
|
clangfixitoperationsextractor.cpp \
|
||||||
|
clangfollowsymbol.cpp \
|
||||||
clangfunctionhintmodel.cpp \
|
clangfunctionhintmodel.cpp \
|
||||||
clanghighlightingmarksreporter.cpp \
|
clanghighlightingmarksreporter.cpp \
|
||||||
clangmodelmanagersupport.cpp \
|
clangmodelmanagersupport.cpp \
|
||||||
@@ -54,6 +55,7 @@ HEADERS += \
|
|||||||
clangeditordocumentprocessor.h \
|
clangeditordocumentprocessor.h \
|
||||||
clangfixitoperation.h \
|
clangfixitoperation.h \
|
||||||
clangfixitoperationsextractor.h \
|
clangfixitoperationsextractor.h \
|
||||||
|
clangfollowsymbol.h \
|
||||||
clangfunctionhintmodel.h \
|
clangfunctionhintmodel.h \
|
||||||
clanghighlightingmarksreporter.h \
|
clanghighlightingmarksreporter.h \
|
||||||
clangisdiagnosticrelatedtolocation.h \
|
clangisdiagnosticrelatedtolocation.h \
|
||||||
|
@@ -71,6 +71,8 @@ QtcPlugin {
|
|||||||
"clangfixitoperation.h",
|
"clangfixitoperation.h",
|
||||||
"clangfixitoperationsextractor.cpp",
|
"clangfixitoperationsextractor.cpp",
|
||||||
"clangfixitoperationsextractor.h",
|
"clangfixitoperationsextractor.h",
|
||||||
|
"clangfollowsymbol.cpp",
|
||||||
|
"clangfollowsymbol.h",
|
||||||
"clangfunctionhintmodel.cpp",
|
"clangfunctionhintmodel.cpp",
|
||||||
"clangfunctionhintmodel.h",
|
"clangfunctionhintmodel.h",
|
||||||
"clanghighlightingmarksreporter.cpp",
|
"clanghighlightingmarksreporter.cpp",
|
||||||
|
83
src/plugins/clangcodemodel/clangfollowsymbol.cpp
Normal file
83
src/plugins/clangcodemodel/clangfollowsymbol.cpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2017 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "clangfollowsymbol.h"
|
||||||
|
#include "clangeditordocumentprocessor.h"
|
||||||
|
#include "texteditor/texteditor.h"
|
||||||
|
#include "texteditor/convenience.h"
|
||||||
|
|
||||||
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
TextEditor::TextEditorWidget::Link ClangFollowSymbol::findLink(
|
||||||
|
const CppTools::CursorInEditor &data,
|
||||||
|
bool resolveTarget,
|
||||||
|
const CPlusPlus::Snapshot &,
|
||||||
|
const CPlusPlus::Document::Ptr &,
|
||||||
|
CppTools::SymbolFinder *,
|
||||||
|
bool)
|
||||||
|
{
|
||||||
|
Link link;
|
||||||
|
|
||||||
|
int lineNumber = 0, positionInBlock = 0;
|
||||||
|
QTextCursor cursor = TextEditor::Convenience::wordStartCursor(data.cursor());
|
||||||
|
TextEditor::Convenience::convertPosition(cursor.document(), cursor.position(), &lineNumber,
|
||||||
|
&positionInBlock);
|
||||||
|
const unsigned line = lineNumber;
|
||||||
|
const unsigned column = positionInBlock + 1;
|
||||||
|
|
||||||
|
if (!resolveTarget)
|
||||||
|
return link;
|
||||||
|
ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(
|
||||||
|
data.filePath().toString());
|
||||||
|
if (!processor)
|
||||||
|
return link;
|
||||||
|
|
||||||
|
QFuture<CppTools::SymbolInfo> info
|
||||||
|
= processor->requestFollowSymbol(static_cast<int>(line),
|
||||||
|
static_cast<int>(column),
|
||||||
|
resolveTarget);
|
||||||
|
if (info.isCanceled())
|
||||||
|
return link;
|
||||||
|
|
||||||
|
while (!info.isFinished()) {
|
||||||
|
if (info.isCanceled())
|
||||||
|
return link;
|
||||||
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
}
|
||||||
|
CppTools::SymbolInfo result = info.result();
|
||||||
|
|
||||||
|
if (result.failedToFollow)
|
||||||
|
return link;
|
||||||
|
|
||||||
|
// We did not fail but the result is empty
|
||||||
|
if (result.fileName.isEmpty())
|
||||||
|
return link;
|
||||||
|
|
||||||
|
return Link(result.fileName, result.startLine, result.startColumn - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangCodeModel
|
45
src/plugins/clangcodemodel/clangfollowsymbol.h
Normal file
45
src/plugins/clangcodemodel/clangfollowsymbol.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2017 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cpptools/followsymbolinterface.h>
|
||||||
|
|
||||||
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangFollowSymbol : public CppTools::FollowSymbolInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link findLink(const CppTools::CursorInEditor &data,
|
||||||
|
bool resolveTarget,
|
||||||
|
const CPlusPlus::Snapshot &,
|
||||||
|
const CPlusPlus::Document::Ptr &,
|
||||||
|
CppTools::SymbolFinder *,
|
||||||
|
bool) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangCodeModel
|
@@ -28,6 +28,7 @@
|
|||||||
#include "clangconstants.h"
|
#include "clangconstants.h"
|
||||||
#include "clangeditordocumentprocessor.h"
|
#include "clangeditordocumentprocessor.h"
|
||||||
#include "clangutils.h"
|
#include "clangutils.h"
|
||||||
|
#include "clangfollowsymbol.h"
|
||||||
|
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <cpptools/cppmodelmanager.h>
|
#include <cpptools/cppmodelmanager.h>
|
||||||
@@ -52,6 +53,12 @@ using namespace ClangCodeModel::Internal;
|
|||||||
|
|
||||||
static ModelManagerSupportClang *m_instance = 0;
|
static ModelManagerSupportClang *m_instance = 0;
|
||||||
|
|
||||||
|
static bool useClangFollowSymbol()
|
||||||
|
{
|
||||||
|
static bool use = qEnvironmentVariableIntValue("QTC_CLANG_FOLLOW_SYMBOL");
|
||||||
|
return use;
|
||||||
|
}
|
||||||
|
|
||||||
static CppTools::CppModelManager *cppModelManager()
|
static CppTools::CppModelManager *cppModelManager()
|
||||||
{
|
{
|
||||||
return CppTools::CppModelManager::instance();
|
return CppTools::CppModelManager::instance();
|
||||||
@@ -63,6 +70,9 @@ ModelManagerSupportClang::ModelManagerSupportClang()
|
|||||||
QTC_CHECK(!m_instance);
|
QTC_CHECK(!m_instance);
|
||||||
m_instance = this;
|
m_instance = this;
|
||||||
|
|
||||||
|
if (useClangFollowSymbol())
|
||||||
|
m_followSymbol.reset(new ClangFollowSymbol);
|
||||||
|
|
||||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||||
connect(editorManager, &Core::EditorManager::editorOpened,
|
connect(editorManager, &Core::EditorManager::editorOpened,
|
||||||
this, &ModelManagerSupportClang::onEditorOpened);
|
this, &ModelManagerSupportClang::onEditorOpened);
|
||||||
@@ -96,6 +106,11 @@ CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssis
|
|||||||
return &m_completionAssistProvider;
|
return &m_completionAssistProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CppTools::FollowSymbolInterface *ModelManagerSupportClang::followSymbolInterface()
|
||||||
|
{
|
||||||
|
return m_followSymbol.get();
|
||||||
|
}
|
||||||
|
|
||||||
CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::editorDocumentProcessor(
|
CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::editorDocumentProcessor(
|
||||||
TextEditor::TextDocument *baseTextDocument)
|
TextEditor::TextDocument *baseTextDocument)
|
||||||
{
|
{
|
||||||
|
@@ -33,6 +33,8 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QMenu;
|
class QMenu;
|
||||||
class QWidget;
|
class QWidget;
|
||||||
@@ -44,6 +46,8 @@ namespace TextEditor { class TextEditorWidget; }
|
|||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangFollowSymbol;
|
||||||
|
|
||||||
class ModelManagerSupportClang:
|
class ModelManagerSupportClang:
|
||||||
public QObject,
|
public QObject,
|
||||||
public CppTools::ModelManagerSupport
|
public CppTools::ModelManagerSupport
|
||||||
@@ -57,6 +61,7 @@ public:
|
|||||||
CppTools::CppCompletionAssistProvider *completionAssistProvider() override;
|
CppTools::CppCompletionAssistProvider *completionAssistProvider() override;
|
||||||
CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(
|
CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(
|
||||||
TextEditor::TextDocument *baseTextDocument) override;
|
TextEditor::TextDocument *baseTextDocument) override;
|
||||||
|
CppTools::FollowSymbolInterface *followSymbolInterface() override;
|
||||||
|
|
||||||
IpcCommunicator &ipcCommunicator();
|
IpcCommunicator &ipcCommunicator();
|
||||||
QString dummyUiHeaderOnDiskDirPath() const;
|
QString dummyUiHeaderOnDiskDirPath() const;
|
||||||
@@ -100,6 +105,7 @@ private:
|
|||||||
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
|
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
|
||||||
IpcCommunicator m_ipcCommunicator;
|
IpcCommunicator m_ipcCommunicator;
|
||||||
ClangCompletionAssistProvider m_completionAssistProvider;
|
ClangCompletionAssistProvider m_completionAssistProvider;
|
||||||
|
std::unique_ptr<ClangFollowSymbol> m_followSymbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModelManagerSupportProviderClang : public CppTools::ModelManagerSupportProvider
|
class ModelManagerSupportProviderClang : public CppTools::ModelManagerSupportProvider
|
||||||
|
@@ -386,12 +386,6 @@ CppEditorDocument::cursorInfo(const CppTools::CursorInfoParams ¶ms)
|
|||||||
return processor()->cursorInfo(params);
|
return processor()->cursorInfo(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<CppTools::SymbolInfo>
|
|
||||||
CppEditorDocument::requestFollowSymbol(int line, int column, bool resolveTarget)
|
|
||||||
{
|
|
||||||
return processor()->requestFollowSymbol(line, column, resolveTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MinimizableInfoBars &CppEditorDocument::minimizableInfoBars() const
|
const MinimizableInfoBars &CppEditorDocument::minimizableInfoBars() const
|
||||||
{
|
{
|
||||||
return m_minimizableInfoBars;
|
return m_minimizableInfoBars;
|
||||||
|
@@ -67,9 +67,6 @@ public:
|
|||||||
ParseContextModel &parseContextModel();
|
ParseContextModel &parseContextModel();
|
||||||
|
|
||||||
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams ¶ms);
|
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams ¶ms);
|
||||||
QFuture<CppTools::SymbolInfo> requestFollowSymbol(int line,
|
|
||||||
int column,
|
|
||||||
bool resolveTarget = true);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void codeWarningsUpdated(unsigned contentsRevision,
|
void codeWarningsUpdated(unsigned contentsRevision,
|
||||||
|
@@ -93,6 +93,9 @@ private slots:
|
|||||||
void test_FollowSymbolUnderCursor_data();
|
void test_FollowSymbolUnderCursor_data();
|
||||||
void test_FollowSymbolUnderCursor();
|
void test_FollowSymbolUnderCursor();
|
||||||
|
|
||||||
|
void test_FollowSymbolUnderCursor_QTCREATORBUG7903_data();
|
||||||
|
void test_FollowSymbolUnderCursor_QTCREATORBUG7903();
|
||||||
|
|
||||||
void test_FollowSymbolUnderCursor_followCall_data();
|
void test_FollowSymbolUnderCursor_followCall_data();
|
||||||
void test_FollowSymbolUnderCursor_followCall();
|
void test_FollowSymbolUnderCursor_followCall();
|
||||||
|
|
||||||
|
@@ -129,8 +129,8 @@ public:
|
|||||||
|
|
||||||
CppLocalRenaming m_localRenaming;
|
CppLocalRenaming m_localRenaming;
|
||||||
CppUseSelectionsUpdater m_useSelectionsUpdater;
|
CppUseSelectionsUpdater m_useSelectionsUpdater;
|
||||||
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
|
|
||||||
CppSelectionChanger m_cppSelectionChanger;
|
CppSelectionChanger m_cppSelectionChanger;
|
||||||
|
FollowSymbolUnderCursor m_builtinFollowSymbol;
|
||||||
CppRefactoringEngine m_builtinRefactoringEngine;
|
CppRefactoringEngine m_builtinRefactoringEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -141,7 +141,6 @@ CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
|
|||||||
, m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
|
, m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
|
||||||
, m_localRenaming(q)
|
, m_localRenaming(q)
|
||||||
, m_useSelectionsUpdater(q)
|
, m_useSelectionsUpdater(q)
|
||||||
, m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
|
|
||||||
, m_cppSelectionChanger()
|
, m_cppSelectionChanger()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -647,12 +646,23 @@ CppEditorWidget::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor,
|
|||||||
if (!d->m_modelManager)
|
if (!d->m_modelManager)
|
||||||
return Link();
|
return Link();
|
||||||
|
|
||||||
return d->m_followSymbolUnderCursor->findLink(cursor,
|
const Utils::FileName &filePath = textDocument()->filePath();
|
||||||
resolveTarget,
|
if (!resolveTarget) {
|
||||||
d->m_modelManager->snapshot(),
|
// TODO: get that part also from clang
|
||||||
d->m_lastSemanticInfo.doc,
|
return d->m_builtinFollowSymbol.findLink(CppTools::CursorInEditor{cursor, filePath, this},
|
||||||
d->m_modelManager->symbolFinder(),
|
resolveTarget,
|
||||||
inNextSplit);
|
d->m_modelManager->snapshot(),
|
||||||
|
d->m_lastSemanticInfo.doc,
|
||||||
|
d->m_modelManager->symbolFinder(),
|
||||||
|
inNextSplit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return followSymbolInterface()->findLink(CppTools::CursorInEditor{cursor, filePath, this},
|
||||||
|
resolveTarget,
|
||||||
|
d->m_modelManager->snapshot(),
|
||||||
|
d->m_lastSemanticInfo.doc,
|
||||||
|
d->m_modelManager->symbolFinder(),
|
||||||
|
inNextSplit);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CppEditorWidget::documentRevision() const
|
unsigned CppEditorWidget::documentRevision() const
|
||||||
@@ -687,6 +697,14 @@ RefactoringEngineInterface *CppEditorWidget::refactoringEngine() const
|
|||||||
: static_cast<RefactoringEngineInterface *>(&d->m_builtinRefactoringEngine);
|
: static_cast<RefactoringEngineInterface *>(&d->m_builtinRefactoringEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CppTools::FollowSymbolInterface *CppEditorWidget::followSymbolInterface() const
|
||||||
|
{
|
||||||
|
CppTools::FollowSymbolInterface *followSymbol
|
||||||
|
= CppTools::CppModelManager::instance()->followSymbolInterface();
|
||||||
|
return followSymbol ? followSymbol
|
||||||
|
: static_cast<CppTools::FollowSymbolInterface *>(&d->m_builtinFollowSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const
|
bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const
|
||||||
{
|
{
|
||||||
return d->m_lastSemanticInfo.doc && d->m_lastSemanticInfo.revision == documentRevision()
|
return d->m_lastSemanticInfo.doc && d->m_lastSemanticInfo.revision == documentRevision()
|
||||||
@@ -973,11 +991,6 @@ void CppEditorWidget::applyDeclDefLinkChanges(bool jumpToMatch)
|
|||||||
updateFunctionDeclDefLink();
|
updateFunctionDeclDefLink();
|
||||||
}
|
}
|
||||||
|
|
||||||
FollowSymbolUnderCursor *CppEditorWidget::followSymbolUnderCursorDelegate()
|
|
||||||
{
|
|
||||||
return d->m_followSymbolUnderCursor.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CppEditorWidget::encourageApply()
|
void CppEditorWidget::encourageApply()
|
||||||
{
|
{
|
||||||
if (d->m_localRenaming.encourageApply())
|
if (d->m_localRenaming.encourageApply())
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
namespace CppTools {
|
namespace CppTools {
|
||||||
class CppEditorOutline;
|
class CppEditorOutline;
|
||||||
class RefactoringEngineInterface;
|
class RefactoringEngineInterface;
|
||||||
|
class FollowSymbolInterface;
|
||||||
class SemanticInfo;
|
class SemanticInfo;
|
||||||
class ProjectPart;
|
class ProjectPart;
|
||||||
}
|
}
|
||||||
@@ -42,7 +43,6 @@ namespace Internal {
|
|||||||
class CppEditorDocument;
|
class CppEditorDocument;
|
||||||
|
|
||||||
class CppEditorWidgetPrivate;
|
class CppEditorWidgetPrivate;
|
||||||
class FollowSymbolUnderCursor;
|
|
||||||
class FunctionDeclDefLink;
|
class FunctionDeclDefLink;
|
||||||
|
|
||||||
class CppEditorWidget : public TextEditor::TextEditorWidget
|
class CppEditorWidget : public TextEditor::TextEditorWidget
|
||||||
@@ -67,8 +67,6 @@ public:
|
|||||||
TextEditor::AssistKind kind,
|
TextEditor::AssistKind kind,
|
||||||
TextEditor::AssistReason reason) const override;
|
TextEditor::AssistReason reason) const override;
|
||||||
|
|
||||||
FollowSymbolUnderCursor *followSymbolUnderCursorDelegate(); // exposed for tests
|
|
||||||
|
|
||||||
void encourageApply() override;
|
void encourageApply() override;
|
||||||
|
|
||||||
void paste() override;
|
void paste() override;
|
||||||
@@ -89,6 +87,8 @@ public:
|
|||||||
static bool isWidgetHighlighted(QWidget *widget);
|
static bool isWidgetHighlighted(QWidget *widget);
|
||||||
|
|
||||||
void updateSemanticInfo();
|
void updateSemanticInfo();
|
||||||
|
|
||||||
|
CppTools::FollowSymbolInterface *followSymbolInterface() const;
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent *e) override;
|
bool event(QEvent *e) override;
|
||||||
void contextMenuEvent(QContextMenuEvent *) override;
|
void contextMenuEvent(QContextMenuEvent *) override;
|
||||||
|
@@ -55,12 +55,6 @@ typedef TextEditorWidget::Link Link;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static bool useClangFollowSymbol()
|
|
||||||
{
|
|
||||||
static bool use = qEnvironmentVariableIntValue("QTC_CLANG_FOLLOW_SYMBOL");
|
|
||||||
return use;
|
|
||||||
}
|
|
||||||
|
|
||||||
class VirtualFunctionHelper {
|
class VirtualFunctionHelper {
|
||||||
public:
|
public:
|
||||||
VirtualFunctionHelper(TypeOfExpression &typeOfExpression,
|
VirtualFunctionHelper(TypeOfExpression &typeOfExpression,
|
||||||
@@ -305,9 +299,9 @@ inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolvedSymbo
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CppEditorWidget::Link attemptFuncDeclDef(const QTextCursor &cursor,
|
CppEditorWidget::Link attemptFuncDeclDef(const QTextCursor &cursor, Snapshot snapshot,
|
||||||
CppEditorWidget *, Snapshot snapshot, const Document::Ptr &document,
|
const Document::Ptr &document,
|
||||||
SymbolFinder *symbolFinder)
|
SymbolFinder *symbolFinder)
|
||||||
{
|
{
|
||||||
Link result;
|
Link result;
|
||||||
QTC_ASSERT(document, return result);
|
QTC_ASSERT(document, return result);
|
||||||
@@ -467,17 +461,11 @@ QString expressionUnderCursorAsString(const QTextCursor &textCursor,
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
FollowSymbolUnderCursor::FollowSymbolUnderCursor(CppEditorWidget *widget)
|
FollowSymbolUnderCursor::FollowSymbolUnderCursor()
|
||||||
: m_widget(widget)
|
: m_virtualFunctionAssistProvider(new VirtualFunctionAssistProvider)
|
||||||
, m_virtualFunctionAssistProvider(new VirtualFunctionAssistProvider)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FollowSymbolUnderCursor::~FollowSymbolUnderCursor()
|
|
||||||
{
|
|
||||||
delete m_virtualFunctionAssistProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int skipMatchingParentheses(const Tokens &tokens, int idx, int initialDepth)
|
static int skipMatchingParentheses(const Tokens &tokens, int idx, int initialDepth)
|
||||||
{
|
{
|
||||||
int j = idx;
|
int j = idx;
|
||||||
@@ -495,61 +483,28 @@ static int skipMatchingParentheses(const Tokens &tokens, int idx, int initialDep
|
|||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FollowSymbolUnderCursor::processorFollowSymbol(uint line, uint column, bool resolveTarget,
|
Link FollowSymbolUnderCursor::findLink(
|
||||||
Link &linkResult)
|
const CppTools::CursorInEditor &data,
|
||||||
{
|
bool resolveTarget,
|
||||||
if (!useClangFollowSymbol())
|
const Snapshot &theSnapshot,
|
||||||
return false;
|
const Document::Ptr &documentFromSemanticInfo,
|
||||||
CppEditorDocument* editorDocument = m_widget->cppEditorDocument();
|
SymbolFinder *symbolFinder,
|
||||||
if (!editorDocument)
|
bool inNextSplit)
|
||||||
return false;
|
|
||||||
|
|
||||||
QFuture<CppTools::SymbolInfo> info
|
|
||||||
= editorDocument->requestFollowSymbol(static_cast<int>(line),
|
|
||||||
static_cast<int>(column),
|
|
||||||
resolveTarget);
|
|
||||||
if (info.isCanceled())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
while (!info.isFinished()) {
|
|
||||||
if (info.isCanceled())
|
|
||||||
return false;
|
|
||||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
||||||
}
|
|
||||||
CppTools::SymbolInfo result = info.result();
|
|
||||||
|
|
||||||
// Try again with built-in code model (happens with some includes)
|
|
||||||
if (result.failedToFollow)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// We did not fail but the result is empty
|
|
||||||
if (result.fileName.isEmpty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
linkResult = Link(result.fileName, result.startLine, result.startColumn - 1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &cursor,
|
|
||||||
bool resolveTarget, const Snapshot &theSnapshot, const Document::Ptr &documentFromSemanticInfo,
|
|
||||||
SymbolFinder *symbolFinder, bool inNextSplit)
|
|
||||||
{
|
{
|
||||||
Link link;
|
Link link;
|
||||||
|
|
||||||
int lineNumber = 0, positionInBlock = 0;
|
int lineNumber = 0, positionInBlock = 0;
|
||||||
m_widget->convertPosition(cursor.position(), &lineNumber, &positionInBlock);
|
QTextCursor cursor = data.cursor();
|
||||||
|
QTextDocument *document = cursor.document();
|
||||||
|
TextEditor::Convenience::convertPosition(document, cursor.position(), &lineNumber,
|
||||||
|
&positionInBlock);
|
||||||
const unsigned line = lineNumber;
|
const unsigned line = lineNumber;
|
||||||
const unsigned column = positionInBlock + 1;
|
const unsigned column = positionInBlock + 1;
|
||||||
|
|
||||||
if (resolveTarget && processorFollowSymbol(line, column, resolveTarget, link))
|
|
||||||
return link;
|
|
||||||
|
|
||||||
Snapshot snapshot = theSnapshot;
|
Snapshot snapshot = theSnapshot;
|
||||||
|
|
||||||
// Move to end of identifier
|
// Move to end of identifier
|
||||||
QTextCursor tc = cursor;
|
QTextCursor tc = cursor;
|
||||||
QTextDocument *document = m_widget->document();
|
|
||||||
QChar ch = document->characterAt(tc.position());
|
QChar ch = document->characterAt(tc.position());
|
||||||
while (CppTools::isValidIdentifierChar(ch)) {
|
while (CppTools::isValidIdentifierChar(ch)) {
|
||||||
tc.movePosition(QTextCursor::NextCharacter);
|
tc.movePosition(QTextCursor::NextCharacter);
|
||||||
@@ -564,7 +519,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
while (document->characterAt(pos).isSpace())
|
while (document->characterAt(pos).isSpace())
|
||||||
++pos;
|
++pos;
|
||||||
if (document->characterAt(pos) == QLatin1Char('(')) {
|
if (document->characterAt(pos) == QLatin1Char('(')) {
|
||||||
link = attemptFuncDeclDef(cursor, m_widget, snapshot, documentFromSemanticInfo,
|
link = attemptFuncDeclDef(cursor, snapshot, documentFromSemanticInfo,
|
||||||
symbolFinder);
|
symbolFinder);
|
||||||
if (link.hasValidLinkText())
|
if (link.hasValidLinkText())
|
||||||
return link;
|
return link;
|
||||||
@@ -636,7 +591,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
&& unsigned(positionInBlock) <= tk.utf16charsEnd()) {
|
&& unsigned(positionInBlock) <= tk.utf16charsEnd()) {
|
||||||
cursorRegionReached = true;
|
cursorRegionReached = true;
|
||||||
if (tk.is(T_OPERATOR)) {
|
if (tk.is(T_OPERATOR)) {
|
||||||
link = attemptFuncDeclDef(cursor, m_widget, theSnapshot,
|
link = attemptFuncDeclDef(cursor, theSnapshot,
|
||||||
documentFromSemanticInfo, symbolFinder);
|
documentFromSemanticInfo, symbolFinder);
|
||||||
if (link.hasValidLinkText())
|
if (link.hasValidLinkText())
|
||||||
return link;
|
return link;
|
||||||
@@ -644,7 +599,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
QTextCursor c = cursor;
|
QTextCursor c = cursor;
|
||||||
c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor,
|
c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor,
|
||||||
positionInBlock - tokens.at(i - 1).utf16charsBegin());
|
positionInBlock - tokens.at(i - 1).utf16charsBegin());
|
||||||
link = attemptFuncDeclDef(c, m_widget, theSnapshot, documentFromSemanticInfo,
|
link = attemptFuncDeclDef(c, theSnapshot, documentFromSemanticInfo,
|
||||||
symbolFinder);
|
symbolFinder);
|
||||||
if (link.hasValidLinkText())
|
if (link.hasValidLinkText())
|
||||||
return link;
|
return link;
|
||||||
@@ -655,8 +610,11 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CppEditorWidget *editorWidget = static_cast<CppEditorWidget *>(data.editorWidget());
|
||||||
|
if (!editorWidget)
|
||||||
|
return link;
|
||||||
// Now we prefer the doc from the snapshot with macros expanded.
|
// Now we prefer the doc from the snapshot with macros expanded.
|
||||||
Document::Ptr doc = snapshot.document(m_widget->textDocument()->filePath());
|
Document::Ptr doc = snapshot.document(editorWidget->textDocument()->filePath());
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
doc = documentFromSemanticInfo;
|
doc = documentFromSemanticInfo;
|
||||||
if (!doc)
|
if (!doc)
|
||||||
@@ -705,7 +663,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
} else if (const Document::MacroUse *use = doc->findMacroUseAt(endOfToken - 1)) {
|
} else if (const Document::MacroUse *use = doc->findMacroUseAt(endOfToken - 1)) {
|
||||||
const QString fileName = use->macro().fileName();
|
const QString fileName = use->macro().fileName();
|
||||||
if (fileName == CppModelManager::editorConfigurationFileName()) {
|
if (fileName == CppModelManager::editorConfigurationFileName()) {
|
||||||
m_widget->showPreProcessorWidget();
|
editorWidget->showPreProcessorWidget();
|
||||||
} else if (fileName != CppModelManager::configurationFileName()) {
|
} else if (fileName != CppModelManager::configurationFileName()) {
|
||||||
const Macro ¯o = use->macro();
|
const Macro ¯o = use->macro();
|
||||||
link.targetFileName = macro.fileName();
|
link.targetFileName = macro.fileName();
|
||||||
@@ -739,7 +697,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
if (Symbol *d = r.declaration()) {
|
if (Symbol *d = r.declaration()) {
|
||||||
if (d->isDeclaration() || d->isFunction()) {
|
if (d->isDeclaration() || d->isFunction()) {
|
||||||
const QString fileName = QString::fromUtf8(d->fileName(), d->fileNameLength());
|
const QString fileName = QString::fromUtf8(d->fileName(), d->fileNameLength());
|
||||||
if (m_widget->textDocument()->filePath().toString() == fileName) {
|
if (editorWidget->textDocument()->filePath().toString() == fileName) {
|
||||||
if (unsigned(lineNumber) == d->line()
|
if (unsigned(lineNumber) == d->line()
|
||||||
&& unsigned(positionInBlock) >= d->column()) { // TODO: check the end
|
&& unsigned(positionInBlock) >= d->column()) { // TODO: check the end
|
||||||
result = r; // take the symbol under cursor.
|
result = r; // take the symbol under cursor.
|
||||||
@@ -748,7 +706,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
}
|
}
|
||||||
} else if (d->isUsingDeclaration()) {
|
} else if (d->isUsingDeclaration()) {
|
||||||
int tokenBeginLineNumber = 0, tokenBeginColumnNumber = 0;
|
int tokenBeginLineNumber = 0, tokenBeginColumnNumber = 0;
|
||||||
m_widget->convertPosition(beginOfToken, &tokenBeginLineNumber,
|
editorWidget->convertPosition(beginOfToken, &tokenBeginLineNumber,
|
||||||
&tokenBeginColumnNumber);
|
&tokenBeginColumnNumber);
|
||||||
if (unsigned(tokenBeginLineNumber) > d->line()
|
if (unsigned(tokenBeginLineNumber) > d->line()
|
||||||
|| (unsigned(tokenBeginLineNumber) == d->line()
|
|| (unsigned(tokenBeginLineNumber) == d->line()
|
||||||
@@ -778,7 +736,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
params.openInNextSplit = inNextSplit;
|
params.openInNextSplit = inNextSplit;
|
||||||
|
|
||||||
if (m_virtualFunctionAssistProvider->configure(params)) {
|
if (m_virtualFunctionAssistProvider->configure(params)) {
|
||||||
m_widget->invokeAssist(FollowSymbol, m_virtualFunctionAssistProvider);
|
editorWidget->invokeAssist(FollowSymbol, m_virtualFunctionAssistProvider.data());
|
||||||
m_virtualFunctionAssistProvider->clearParams();
|
m_virtualFunctionAssistProvider->clearParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,12 +785,13 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
|
|||||||
return Link();
|
return Link();
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualFunctionAssistProvider *FollowSymbolUnderCursor::virtualFunctionAssistProvider()
|
QSharedPointer<VirtualFunctionAssistProvider> FollowSymbolUnderCursor::virtualFunctionAssistProvider()
|
||||||
{
|
{
|
||||||
return m_virtualFunctionAssistProvider;
|
return m_virtualFunctionAssistProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FollowSymbolUnderCursor::setVirtualFunctionAssistProvider(VirtualFunctionAssistProvider *provider)
|
void FollowSymbolUnderCursor::setVirtualFunctionAssistProvider(
|
||||||
|
const QSharedPointer<VirtualFunctionAssistProvider> &provider)
|
||||||
{
|
{
|
||||||
m_virtualFunctionAssistProvider = provider;
|
m_virtualFunctionAssistProvider = provider;
|
||||||
}
|
}
|
||||||
|
@@ -25,44 +25,31 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cplusplus/CppDocument.h>
|
#include <cpptools/followsymbolinterface.h>
|
||||||
#include <texteditor/texteditor.h>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QTextCursor;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace CppTools { class SymbolFinder; }
|
|
||||||
|
|
||||||
namespace CppEditor {
|
namespace CppEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class CppEditorWidget;
|
|
||||||
class VirtualFunctionAssistProvider;
|
class VirtualFunctionAssistProvider;
|
||||||
|
|
||||||
class FollowSymbolUnderCursor
|
class FollowSymbolUnderCursor : public CppTools::FollowSymbolInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef TextEditor::TextEditorWidget::Link Link;
|
FollowSymbolUnderCursor();
|
||||||
|
|
||||||
FollowSymbolUnderCursor(CppEditorWidget *widget);
|
Link findLink(const CppTools::CursorInEditor &data,
|
||||||
~FollowSymbolUnderCursor();
|
bool resolveTarget,
|
||||||
|
|
||||||
Link findLink(const QTextCursor &cursor, bool resolveTarget,
|
|
||||||
const CPlusPlus::Snapshot &snapshot,
|
const CPlusPlus::Snapshot &snapshot,
|
||||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||||
CppTools::SymbolFinder *symbolFinder, bool inNextSplit);
|
CppTools::SymbolFinder *symbolFinder,
|
||||||
|
bool inNextSplit) override;
|
||||||
|
|
||||||
VirtualFunctionAssistProvider *virtualFunctionAssistProvider();
|
QSharedPointer<VirtualFunctionAssistProvider> virtualFunctionAssistProvider();
|
||||||
void setVirtualFunctionAssistProvider(VirtualFunctionAssistProvider *provider);
|
void setVirtualFunctionAssistProvider(
|
||||||
|
const QSharedPointer<VirtualFunctionAssistProvider> &provider);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Try to follow symbol with clang processor
|
QSharedPointer<VirtualFunctionAssistProvider> m_virtualFunctionAssistProvider;
|
||||||
// Returns false if it has failed and we want to try again with built-in one
|
|
||||||
bool processorFollowSymbol(uint line, uint column, bool resolveTarget,
|
|
||||||
Link &result);
|
|
||||||
CppEditorWidget *m_widget;
|
|
||||||
VirtualFunctionAssistProvider *m_virtualFunctionAssistProvider;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include "cppvirtualfunctionproposalitem.h"
|
#include "cppvirtualfunctionproposalitem.h"
|
||||||
|
|
||||||
#include <cpptools/cpptoolstestcase.h>
|
#include <cpptools/cpptoolstestcase.h>
|
||||||
|
#include <cpptools/cppmodelmanager.h>
|
||||||
|
|
||||||
#include <texteditor/codeassist/genericproposalmodel.h>
|
#include <texteditor/codeassist/genericproposalmodel.h>
|
||||||
#include <texteditor/codeassist/iassistprocessor.h>
|
#include <texteditor/codeassist/iassistprocessor.h>
|
||||||
@@ -326,19 +327,37 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case FollowSymbolUnderCursorAction: {
|
case FollowSymbolUnderCursorAction: {
|
||||||
CppEditorWidget *widget = initialTestFile->m_editorWidget;
|
CppEditorWidget *widget = initialTestFile->m_editorWidget;
|
||||||
FollowSymbolUnderCursor *delegate = widget->followSymbolUnderCursorDelegate();
|
FollowSymbolInterface* delegate = widget->followSymbolInterface();
|
||||||
VirtualFunctionAssistProvider *original = delegate->virtualFunctionAssistProvider();
|
if (!delegate)
|
||||||
|
QFAIL("No follow symbol interface");
|
||||||
|
auto* builtinFollowSymbol = dynamic_cast<FollowSymbolUnderCursor *>(delegate);
|
||||||
|
if (!builtinFollowSymbol) {
|
||||||
|
if (filePaths.size() > 1)
|
||||||
|
QSKIP("Clang FollowSymbol does not currently support multiple files (except cpp+header)");
|
||||||
|
const QString curTestName = QLatin1String(QTest::currentTestFunction());
|
||||||
|
if (curTestName == "test_FollowSymbolUnderCursor_QObject_connect"
|
||||||
|
|| curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall"
|
||||||
|
|| curTestName == "test_FollowSymbolUnderCursor_QTCREATORBUG7903") {
|
||||||
|
QSKIP((curTestName + " is not supported by Clang FollowSymbol").toLatin1());
|
||||||
|
}
|
||||||
|
|
||||||
|
initialTestFile->m_editorWidget->openLinkUnderCursor();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<VirtualFunctionAssistProvider> original
|
||||||
|
= builtinFollowSymbol->virtualFunctionAssistProvider();
|
||||||
|
|
||||||
// Set test provider, run and get results
|
// Set test provider, run and get results
|
||||||
QScopedPointer<VirtualFunctionTestAssistProvider> testProvider(
|
QSharedPointer<VirtualFunctionTestAssistProvider> testProvider(
|
||||||
new VirtualFunctionTestAssistProvider(widget));
|
new VirtualFunctionTestAssistProvider(widget));
|
||||||
delegate->setVirtualFunctionAssistProvider(testProvider.data());
|
builtinFollowSymbol->setVirtualFunctionAssistProvider(testProvider);
|
||||||
initialTestFile->m_editorWidget->openLinkUnderCursor();
|
initialTestFile->m_editorWidget->openLinkUnderCursor();
|
||||||
immediateVirtualSymbolResults = testProvider->m_immediateItems;
|
immediateVirtualSymbolResults = testProvider->m_immediateItems;
|
||||||
finalVirtualSymbolResults = testProvider->m_finalItems;
|
finalVirtualSymbolResults = testProvider->m_finalItems;
|
||||||
|
|
||||||
// Restore original test provider
|
// Restore original test provider
|
||||||
delegate->setVirtualFunctionAssistProvider(original);
|
builtinFollowSymbol->setVirtualFunctionAssistProvider(original);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SwitchBetweenMethodDeclarationDefinitionAction:
|
case SwitchBetweenMethodDeclarationDefinitionAction:
|
||||||
@@ -870,41 +889,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data()
|
|||||||
"@Container<int> container;\n"
|
"@Container<int> container;\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
QTest::newRow("using_QTCREATORBUG7903_globalNamespace") << _(
|
|
||||||
"namespace NS {\n"
|
|
||||||
"class Foo {};\n"
|
|
||||||
"}\n"
|
|
||||||
"using NS::$Foo;\n"
|
|
||||||
"void fun()\n"
|
|
||||||
"{\n"
|
|
||||||
" @Foo foo;\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
QTest::newRow("using_QTCREATORBUG7903_namespace") << _(
|
|
||||||
"namespace NS {\n"
|
|
||||||
"class Foo {};\n"
|
|
||||||
"}\n"
|
|
||||||
"namespace NS1 {\n"
|
|
||||||
"void fun()\n"
|
|
||||||
"{\n"
|
|
||||||
" using NS::$Foo;\n"
|
|
||||||
" @Foo foo;\n"
|
|
||||||
"}\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
QTest::newRow("using_QTCREATORBUG7903_insideFunction") << _(
|
|
||||||
"namespace NS {\n"
|
|
||||||
"class Foo {};\n"
|
|
||||||
"}\n"
|
|
||||||
"void fun()\n"
|
|
||||||
"{\n"
|
|
||||||
" using NS::$Foo;\n"
|
|
||||||
" @Foo foo;\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
QTest::newRow("matchFunctionSignature_Follow_1") << _(
|
QTest::newRow("matchFunctionSignature_Follow_1") << _(
|
||||||
"class Foo {\n"
|
"class Foo {\n"
|
||||||
" void @foo(int);\n"
|
" void @foo(int);\n"
|
||||||
@@ -993,6 +977,8 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data()
|
|||||||
);
|
);
|
||||||
|
|
||||||
QTest::newRow("template_alias") << _(
|
QTest::newRow("template_alias") << _(
|
||||||
|
"template<class T>"
|
||||||
|
"class Bar;"
|
||||||
"template<class $T>\n"
|
"template<class $T>\n"
|
||||||
"using Foo = Bar<@T>;\n"
|
"using Foo = Bar<@T>;\n"
|
||||||
);
|
);
|
||||||
@@ -1004,6 +990,51 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor()
|
|||||||
F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source));
|
F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppEditorPlugin::test_FollowSymbolUnderCursor_QTCREATORBUG7903_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QByteArray>("source");
|
||||||
|
QTest::newRow("using_QTCREATORBUG7903_globalNamespace") << _(
|
||||||
|
"namespace NS {\n"
|
||||||
|
"class Foo {};\n"
|
||||||
|
"}\n"
|
||||||
|
"using NS::$Foo;\n"
|
||||||
|
"void fun()\n"
|
||||||
|
"{\n"
|
||||||
|
" @Foo foo;\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
QTest::newRow("using_QTCREATORBUG7903_namespace") << _(
|
||||||
|
"namespace NS {\n"
|
||||||
|
"class Foo {};\n"
|
||||||
|
"}\n"
|
||||||
|
"namespace NS1 {\n"
|
||||||
|
"void fun()\n"
|
||||||
|
"{\n"
|
||||||
|
" using NS::$Foo;\n"
|
||||||
|
" @Foo foo;\n"
|
||||||
|
"}\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
QTest::newRow("using_QTCREATORBUG7903_insideFunction") << _(
|
||||||
|
"namespace NS {\n"
|
||||||
|
"class Foo {};\n"
|
||||||
|
"}\n"
|
||||||
|
"void fun()\n"
|
||||||
|
"{\n"
|
||||||
|
" using NS::$Foo;\n"
|
||||||
|
" @Foo foo;\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppEditorPlugin::test_FollowSymbolUnderCursor_QTCREATORBUG7903()
|
||||||
|
{
|
||||||
|
QFETCH(QByteArray, source);
|
||||||
|
F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source));
|
||||||
|
}
|
||||||
|
|
||||||
void CppEditorPlugin::test_FollowSymbolUnderCursor_followCall_data()
|
void CppEditorPlugin::test_FollowSymbolUnderCursor_followCall_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QByteArray>("variableDeclaration"); // without semicolon, can be ""
|
QTest::addColumn<QByteArray>("variableDeclaration"); // without semicolon, can be ""
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#include "cpptoolsreuse.h"
|
#include "cpptoolsreuse.h"
|
||||||
#include "editordocumenthandle.h"
|
#include "editordocumenthandle.h"
|
||||||
#include "symbolfinder.h"
|
#include "symbolfinder.h"
|
||||||
|
#include "followsymbolinterface.h"
|
||||||
|
|
||||||
#include <coreplugin/documentmanager.h>
|
#include <coreplugin/documentmanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -274,6 +275,11 @@ RefactoringEngineInterface *CppModelManager::refactoringEngine()
|
|||||||
return instance()->d->m_refactoringEngine;
|
return instance()->d->m_refactoringEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FollowSymbolInterface *CppModelManager::followSymbolInterface() const
|
||||||
|
{
|
||||||
|
return d->m_activeModelManagerSupport->followSymbolInterface();
|
||||||
|
}
|
||||||
|
|
||||||
QString CppModelManager::configurationFileName()
|
QString CppModelManager::configurationFileName()
|
||||||
{
|
{
|
||||||
return Preprocessor::configurationFileName();
|
return Preprocessor::configurationFileName();
|
||||||
|
@@ -54,6 +54,7 @@ class CppEditorDocumentHandle;
|
|||||||
class CppIndexingSupport;
|
class CppIndexingSupport;
|
||||||
class ModelManagerSupportProvider;
|
class ModelManagerSupportProvider;
|
||||||
class RefactoringEngineInterface;
|
class RefactoringEngineInterface;
|
||||||
|
class FollowSymbolInterface;
|
||||||
class SymbolFinder;
|
class SymbolFinder;
|
||||||
class WorkingCopy;
|
class WorkingCopy;
|
||||||
|
|
||||||
@@ -152,6 +153,7 @@ public:
|
|||||||
CppCompletionAssistProvider *completionAssistProvider() const;
|
CppCompletionAssistProvider *completionAssistProvider() const;
|
||||||
BaseEditorDocumentProcessor *editorDocumentProcessor(
|
BaseEditorDocumentProcessor *editorDocumentProcessor(
|
||||||
TextEditor::TextDocument *baseTextDocument) const;
|
TextEditor::TextDocument *baseTextDocument) const;
|
||||||
|
FollowSymbolInterface *followSymbolInterface() const;
|
||||||
|
|
||||||
void setIndexingSupport(CppIndexingSupport *indexingSupport);
|
void setIndexingSupport(CppIndexingSupport *indexingSupport);
|
||||||
CppIndexingSupport *indexingSupport();
|
CppIndexingSupport *indexingSupport();
|
||||||
|
@@ -36,6 +36,7 @@ namespace CppTools {
|
|||||||
|
|
||||||
class BaseEditorDocumentProcessor;
|
class BaseEditorDocumentProcessor;
|
||||||
class CppCompletionAssistProvider;
|
class CppCompletionAssistProvider;
|
||||||
|
class FollowSymbolInterface;
|
||||||
|
|
||||||
class CPPTOOLS_EXPORT ModelManagerSupport
|
class CPPTOOLS_EXPORT ModelManagerSupport
|
||||||
{
|
{
|
||||||
@@ -48,6 +49,7 @@ public:
|
|||||||
virtual CppCompletionAssistProvider *completionAssistProvider() = 0;
|
virtual CppCompletionAssistProvider *completionAssistProvider() = 0;
|
||||||
virtual BaseEditorDocumentProcessor *editorDocumentProcessor(
|
virtual BaseEditorDocumentProcessor *editorDocumentProcessor(
|
||||||
TextEditor::TextDocument *baseTextDocument) = 0;
|
TextEditor::TextDocument *baseTextDocument) = 0;
|
||||||
|
virtual FollowSymbolInterface *followSymbolInterface() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPPTOOLS_EXPORT ModelManagerSupportProvider
|
class CPPTOOLS_EXPORT ModelManagerSupportProvider
|
||||||
|
@@ -69,3 +69,8 @@ CppCompletionAssistProvider *ModelManagerSupportInternal::completionAssistProvid
|
|||||||
{
|
{
|
||||||
return m_completionAssistProvider.data();
|
return m_completionAssistProvider.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FollowSymbolInterface *ModelManagerSupportInternal::followSymbolInterface()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
@@ -43,6 +43,7 @@ public:
|
|||||||
virtual CppCompletionAssistProvider *completionAssistProvider();
|
virtual CppCompletionAssistProvider *completionAssistProvider();
|
||||||
virtual BaseEditorDocumentProcessor *editorDocumentProcessor(
|
virtual BaseEditorDocumentProcessor *editorDocumentProcessor(
|
||||||
TextEditor::TextDocument *baseTextDocument);
|
TextEditor::TextDocument *baseTextDocument);
|
||||||
|
FollowSymbolInterface *followSymbolInterface() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider;
|
QScopedPointer<CppCompletionAssistProvider> m_completionAssistProvider;
|
||||||
|
@@ -63,6 +63,7 @@ HEADERS += \
|
|||||||
cppworkingcopy.h \
|
cppworkingcopy.h \
|
||||||
doxygengenerator.h \
|
doxygengenerator.h \
|
||||||
editordocumenthandle.h \
|
editordocumenthandle.h \
|
||||||
|
followsymbolinterface.h \
|
||||||
functionutils.h \
|
functionutils.h \
|
||||||
generatedcodemodelsupport.h \
|
generatedcodemodelsupport.h \
|
||||||
includeutils.h \
|
includeutils.h \
|
||||||
|
@@ -164,6 +164,7 @@ Project {
|
|||||||
"doxygengenerator.h",
|
"doxygengenerator.h",
|
||||||
"editordocumenthandle.cpp",
|
"editordocumenthandle.cpp",
|
||||||
"editordocumenthandle.h",
|
"editordocumenthandle.h",
|
||||||
|
"followsymbolinterface.h",
|
||||||
"functionutils.cpp",
|
"functionutils.cpp",
|
||||||
"functionutils.h",
|
"functionutils.h",
|
||||||
"generatedcodemodelsupport.cpp",
|
"generatedcodemodelsupport.cpp",
|
||||||
|
53
src/plugins/cpptools/followsymbolinterface.h
Normal file
53
src/plugins/cpptools/followsymbolinterface.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2017 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cpptools_global.h"
|
||||||
|
#include "cursorineditor.h"
|
||||||
|
|
||||||
|
#include <cplusplus/CppDocument.h>
|
||||||
|
|
||||||
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
|
namespace CppTools {
|
||||||
|
|
||||||
|
class SymbolFinder;
|
||||||
|
|
||||||
|
class CPPTOOLS_EXPORT FollowSymbolInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Link = TextEditor::TextEditorWidget::Link;
|
||||||
|
|
||||||
|
virtual ~FollowSymbolInterface() {}
|
||||||
|
virtual Link findLink(const CursorInEditor &data,
|
||||||
|
bool resolveTarget,
|
||||||
|
const CPlusPlus::Snapshot &snapshot,
|
||||||
|
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||||
|
SymbolFinder *symbolFinder,
|
||||||
|
bool inNextSplit) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CppTools
|
@@ -95,6 +95,13 @@ static bool isValidIdentifierChar(const QChar &c)
|
|||||||
|| c.isLowSurrogate();
|
|| c.isLowSurrogate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isAfterOperatorKeyword(QTextCursor cursor)
|
||||||
|
{
|
||||||
|
cursor.movePosition(QTextCursor::PreviousWord);
|
||||||
|
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||||
|
return cursor.selectedText() == "operator";
|
||||||
|
}
|
||||||
|
|
||||||
QTextCursor wordStartCursor(const QTextCursor &textCursor)
|
QTextCursor wordStartCursor(const QTextCursor &textCursor)
|
||||||
{
|
{
|
||||||
const int originalPosition = textCursor.position();
|
const int originalPosition = textCursor.position();
|
||||||
@@ -108,6 +115,8 @@ QTextCursor wordStartCursor(const QTextCursor &textCursor)
|
|||||||
if (isValidIdentifierChar(c))
|
if (isValidIdentifierChar(c))
|
||||||
cursor.movePosition(QTextCursor::PreviousWord);
|
cursor.movePosition(QTextCursor::PreviousWord);
|
||||||
}
|
}
|
||||||
|
if (isAfterOperatorKeyword(cursor))
|
||||||
|
cursor.movePosition(QTextCursor::PreviousWord);
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
@@ -90,6 +90,20 @@ private:
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
static SourceRange getOperatorRange(const CXTranslationUnit tu,
|
||||||
|
const Tokens &tokens,
|
||||||
|
uint operatorIndex)
|
||||||
|
{
|
||||||
|
const CXSourceLocation start = clang_getTokenLocation(tu, tokens.data[operatorIndex]);
|
||||||
|
operatorIndex += 2;
|
||||||
|
while (operatorIndex < tokens.tokenCount
|
||||||
|
&& !(ClangString(clang_getTokenSpelling(tu, tokens.data[operatorIndex])) == "(")) {
|
||||||
|
++operatorIndex;
|
||||||
|
}
|
||||||
|
const CXSourceLocation end = clang_getTokenLocation(tu, tokens.data[operatorIndex]);
|
||||||
|
return SourceRange(clang_getRange(start, end));
|
||||||
|
}
|
||||||
|
|
||||||
static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
|
static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
|
||||||
const Utf8String &tokenStr)
|
const Utf8String &tokenStr)
|
||||||
{
|
{
|
||||||
@@ -99,10 +113,14 @@ static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
|
|||||||
if (!(tokenStr == ClangString(clang_getTokenSpelling(tu, tokens.data[i]))))
|
if (!(tokenStr == ClangString(clang_getTokenSpelling(tu, tokens.data[i]))))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (cursor.isFunctionLike()
|
if (cursor.isFunctionLike() || cursor.isConstructorOrDestructor()) {
|
||||||
&& (i+1 > tokens.tokenCount
|
if (tokenStr == "operator")
|
||||||
|| !(ClangString(clang_getTokenSpelling(tu, tokens.data[i+1])) == "("))) {
|
return getOperatorRange(tu, tokens, i);
|
||||||
continue;
|
|
||||||
|
if (i+1 > tokens.tokenCount
|
||||||
|
|| !(ClangString(clang_getTokenSpelling(tu, tokens.data[i+1])) == "(")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return SourceRange(clang_getTokenExtent(tu, tokens.data[i]));
|
return SourceRange(clang_getTokenExtent(tu, tokens.data[i]));
|
||||||
}
|
}
|
||||||
|
@@ -351,6 +351,34 @@ TEST_F(FollowSymbol, CursorAfterNamespace)
|
|||||||
ASSERT_THAT(namespaceDefinition, MatchesFileSourceRange(QString(""), 0, 0, 0));
|
ASSERT_THAT(namespaceDefinition, MatchesFileSourceRange(QString(""), 0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(FollowSymbol, CursorOnOneSymbolOperatorDefinition)
|
||||||
|
{
|
||||||
|
const auto namespaceDefinition = followSymbol(76, 13);
|
||||||
|
|
||||||
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(72, 9, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FollowSymbol, CursorOnTwoSymbolOperatorDefinition)
|
||||||
|
{
|
||||||
|
const auto namespaceDefinition = followSymbol(80, 15);
|
||||||
|
|
||||||
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(73, 10, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FollowSymbol, CursorOnOneSymbolOperatorDeclaration)
|
||||||
|
{
|
||||||
|
const auto namespaceDefinition = followSymbol(72, 12);
|
||||||
|
|
||||||
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(76, 10, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FollowSymbol, CursorOnTwoSymbolOperatorDeclaration)
|
||||||
|
{
|
||||||
|
const auto namespaceDefinition = followSymbol(73, 12);
|
||||||
|
|
||||||
|
ASSERT_THAT(namespaceDefinition, MatchesSourceRange(80, 11, 10));
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Data> FollowSymbol::d;
|
std::unique_ptr<Data> FollowSymbol::d;
|
||||||
|
|
||||||
void FollowSymbol::SetUpTestCase()
|
void FollowSymbol::SetUpTestCase()
|
||||||
|
@@ -65,3 +65,18 @@ FooClass::FooClass() {
|
|||||||
int main() {
|
int main() {
|
||||||
return foo() + FooClass::mememember + TEST_DEFINE;
|
return foo() + FooClass::mememember + TEST_DEFINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Bar
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int operator&();
|
||||||
|
Bar& operator[](int);
|
||||||
|
};
|
||||||
|
|
||||||
|
int Bar::operator&() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bar& Bar::operator[](int) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user