forked from qt-creator/qt-creator
ClangCodeModel: Add test for "follow symbol"
These are the tests from clangbackend, so we are now up to par coverage- wise. Change-Id: I7b8a63109bff17745782a646f684fd795f732672 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -205,7 +205,8 @@ QVector<QObject *> ClangCodeModelPlugin::createTestObjects() const
|
|||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
new Tests::ClangCodeCompletionTest,
|
new Tests::ClangCodeCompletionTest,
|
||||||
new Tests::ClangdTests,
|
new Tests::ClangdTestFindReferences,
|
||||||
|
new Tests::ClangdTestFollowSymbol,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -897,7 +897,6 @@ void ClangdClient::followSymbol(
|
|||||||
void ClangdClient::Private::handleGotoDefinitionResult()
|
void ClangdClient::Private::handleGotoDefinitionResult()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(followSymbolData->defLink.hasValidTarget(), return);
|
QTC_ASSERT(followSymbolData->defLink.hasValidTarget(), return);
|
||||||
QTC_ASSERT(followSymbolData->cursorNode.isValid(), return);
|
|
||||||
|
|
||||||
qCDebug(clangdLog) << "handling go to definition result";
|
qCDebug(clangdLog) << "handling go to definition result";
|
||||||
|
|
||||||
|
@@ -78,7 +78,7 @@ public:
|
|||||||
QString error;
|
QString error;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CompilationDbPurpose { Project, CodeModel };
|
enum class CompilationDbPurpose { Project, CodeModel };
|
||||||
GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo,
|
GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo,
|
||||||
CompilationDbPurpose purpose);
|
CompilationDbPurpose purpose);
|
||||||
|
|
||||||
|
@@ -35,7 +35,6 @@
|
|||||||
#include <cpptools/cpptoolsreuse.h>
|
#include <cpptools/cpptoolsreuse.h>
|
||||||
#include <cpptools/cpptoolstestcase.h>
|
#include <cpptools/cpptoolstestcase.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/find/searchresultitem.h>
|
|
||||||
#include <projectexplorer/kitmanager.h>
|
#include <projectexplorer/kitmanager.h>
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/projectexplorer.h>
|
#include <projectexplorer/projectexplorer.h>
|
||||||
@@ -43,6 +42,7 @@
|
|||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
@@ -56,7 +56,19 @@ namespace ClangCodeModel {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
namespace Tests {
|
namespace Tests {
|
||||||
|
|
||||||
void ClangdTests::initTestCase()
|
ClangdTest::~ClangdTest()
|
||||||
|
{
|
||||||
|
if (m_project)
|
||||||
|
ProjectExplorerPlugin::unloadProject(m_project);
|
||||||
|
delete m_projectDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::FilePath ClangdTest::filePath(const QString &fileName) const
|
||||||
|
{
|
||||||
|
return Utils::FilePath::fromString(m_projectDir->absolutePath(fileName.toLocal8Bit()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangdTest::initTestCase()
|
||||||
{
|
{
|
||||||
const auto settings = CppTools::codeModelSettings();
|
const auto settings = CppTools::codeModelSettings();
|
||||||
const QString clangdFromEnv = qEnvironmentVariable("QTC_CLANGD");
|
const QString clangdFromEnv = qEnvironmentVariable("QTC_CLANGD");
|
||||||
@@ -66,249 +78,284 @@ void ClangdTests::initTestCase()
|
|||||||
if (clangd.isEmpty() || !clangd.exists())
|
if (clangd.isEmpty() || !clangd.exists())
|
||||||
QSKIP("clangd binary not found");
|
QSKIP("clangd binary not found");
|
||||||
settings->setUseClangd(true);
|
settings->setUseClangd(true);
|
||||||
|
|
||||||
|
// Find suitable kit.
|
||||||
|
m_kit = Utils::findOr(KitManager::kits(), nullptr, [](const Kit *k) {
|
||||||
|
return k->isValid() && QtSupport::QtKitAspect::qtVersion(k);
|
||||||
|
});
|
||||||
|
if (!m_kit)
|
||||||
|
QSKIP("The test requires at least one valid kit with a valid Qt");
|
||||||
|
|
||||||
|
// Copy project out of qrc file, open it, and set up target.
|
||||||
|
m_projectDir = new TemporaryCopiedDir(qrcPath(QFileInfo(m_projectFileName)
|
||||||
|
.baseName().toLocal8Bit()));
|
||||||
|
QVERIFY(m_projectDir->isValid());
|
||||||
|
const auto openProjectResult = ProjectExplorerPlugin::openProject(
|
||||||
|
m_projectDir->absolutePath(m_projectFileName.toUtf8()));
|
||||||
|
QVERIFY2(openProjectResult, qPrintable(openProjectResult.errorMessage()));
|
||||||
|
m_project = openProjectResult.project();
|
||||||
|
m_project->configureAsExampleProject(m_kit);
|
||||||
|
|
||||||
|
// Setting up the project should result in a clangd client being created.
|
||||||
|
// Wait until that has happened.
|
||||||
|
const auto modelManagerSupport = ClangModelManagerSupport::instance();
|
||||||
|
m_client = modelManagerSupport->clientForProject(openProjectResult.project());
|
||||||
|
if (!m_client) {
|
||||||
|
QVERIFY(waitForSignalOrTimeout(modelManagerSupport,
|
||||||
|
&ClangModelManagerSupport::createdClient, timeOutInMs()));
|
||||||
|
m_client = modelManagerSupport->clientForProject(m_project);
|
||||||
|
}
|
||||||
|
QVERIFY(m_client);
|
||||||
|
m_client->enableTesting();
|
||||||
|
|
||||||
|
// Wait until the client is fully initialized, i.e. it's completed the handshake
|
||||||
|
// with the server.
|
||||||
|
if (!m_client->reachable())
|
||||||
|
QVERIFY(waitForSignalOrTimeout(m_client, &ClangdClient::initialized, timeOutInMs()));
|
||||||
|
QVERIFY(m_client->reachable());
|
||||||
|
|
||||||
|
// The kind of AST support we need was introduced in LLVM 13.
|
||||||
|
if (m_minVersion != -1 && m_client->versionNumber() < QVersionNumber(m_minVersion))
|
||||||
|
QSKIP("clangd is too old");
|
||||||
|
|
||||||
|
// Wait for index to build.
|
||||||
|
if (!m_client->isFullyIndexed())
|
||||||
|
QVERIFY(waitForSignalOrTimeout(m_client, &ClangdClient::indexingFinished, timeOutInMs()));
|
||||||
|
QVERIFY(m_client->isFullyIndexed());
|
||||||
|
|
||||||
|
// Open cpp documents.
|
||||||
|
for (const QString &sourceFileName : qAsConst(m_sourceFileNames)) {
|
||||||
|
const auto sourceFilePath = Utils::FilePath::fromString(
|
||||||
|
m_projectDir->absolutePath(sourceFileName.toLocal8Bit()));
|
||||||
|
QVERIFY2(sourceFilePath.exists(), qPrintable(sourceFilePath.toUserOutput()));
|
||||||
|
IEditor * const editor = EditorManager::openEditor(sourceFilePath);
|
||||||
|
QVERIFY(editor);
|
||||||
|
const auto doc = qobject_cast<TextEditor::TextDocument *>(editor->document());
|
||||||
|
QVERIFY(doc);
|
||||||
|
QVERIFY(m_client->documentForFilePath(sourceFilePath) == doc);
|
||||||
|
m_sourceDocuments.insert(sourceFileName, doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangdTestFindReferences::ClangdTestFindReferences()
|
||||||
|
{
|
||||||
|
setProjectFileName("find-usages.pro");
|
||||||
|
setSourceFileNames({"defs.h", "main.cpp"});
|
||||||
|
setMinimumVersion(13);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangdTestFindReferences::initTestCase()
|
||||||
|
{
|
||||||
|
ClangdTest::initTestCase();
|
||||||
|
connect(client(), &ClangdClient::foundReferences, this,
|
||||||
|
[this](const QList<SearchResultItem> &results) {
|
||||||
|
if (results.isEmpty())
|
||||||
|
return;
|
||||||
|
if (results.first().path().first().endsWith("defs.h"))
|
||||||
|
m_actualResults = results + m_actualResults; // Guarantee expected file order.
|
||||||
|
else
|
||||||
|
m_actualResults += results;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangdTestFindReferences::test_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("fileName");
|
||||||
|
QTest::addColumn<int>("pos");
|
||||||
|
using ItemList = QList<SearchResultItem>;
|
||||||
|
QTest::addColumn<ItemList>("expectedResults");
|
||||||
|
|
||||||
|
static const auto makeItem = [](int line, int column, Usage::Type type) {
|
||||||
|
SearchResultItem item;
|
||||||
|
item.setMainRange(line, column, 0);
|
||||||
|
item.setUserData(int(type));
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
QTest::newRow("struct member") << "defs.h" << 55 << ItemList{
|
||||||
|
makeItem(2, 17, Usage::Type::Read), makeItem(3, 15, Usage::Type::Declaration),
|
||||||
|
makeItem(6, 17, Usage::Type::WritableRef), makeItem(8, 11, Usage::Type::WritableRef),
|
||||||
|
makeItem(9, 13, Usage::Type::WritableRef), makeItem(10, 12, Usage::Type::WritableRef),
|
||||||
|
makeItem(11, 13, Usage::Type::WritableRef), makeItem(12, 14, Usage::Type::WritableRef),
|
||||||
|
makeItem(13, 26, Usage::Type::WritableRef), makeItem(14, 23, Usage::Type::Read),
|
||||||
|
makeItem(15, 14, Usage::Type::Read), makeItem(16, 24, Usage::Type::WritableRef),
|
||||||
|
makeItem(17, 15, Usage::Type::WritableRef), makeItem(18, 22, Usage::Type::Read),
|
||||||
|
makeItem(19, 12, Usage::Type::WritableRef), makeItem(20, 12, Usage::Type::Read),
|
||||||
|
makeItem(21, 13, Usage::Type::WritableRef), makeItem(22, 13, Usage::Type::Read),
|
||||||
|
makeItem(23, 12, Usage::Type::Read), makeItem(42, 20, Usage::Type::Read),
|
||||||
|
makeItem(44, 15, Usage::Type::Read), makeItem(47, 15, Usage::Type::Write),
|
||||||
|
makeItem(50, 11, Usage::Type::Read), makeItem(51, 11, Usage::Type::Write),
|
||||||
|
makeItem(52, 9, Usage::Type::Write), makeItem(53, 7, Usage::Type::Write),
|
||||||
|
makeItem(56, 7, Usage::Type::Write), makeItem(56, 25, Usage::Type::Other),
|
||||||
|
makeItem(58, 13, Usage::Type::Read), makeItem(58, 25, Usage::Type::Read),
|
||||||
|
makeItem(59, 7, Usage::Type::Write), makeItem(59, 24, Usage::Type::Read)};
|
||||||
|
QTest::newRow("constructor member initialization") << "defs.h" << 68 << ItemList{
|
||||||
|
makeItem(2, 10, Usage::Type::Write), makeItem(4, 8, Usage::Type::Declaration)};
|
||||||
|
QTest::newRow("direct member initialization") << "defs.h" << 101 << ItemList{
|
||||||
|
makeItem(5, 21, Usage::Type::Initialization), makeItem(45, 16, Usage::Type::Read)};
|
||||||
|
|
||||||
|
// FIXME: The override gets reported twice. clangd bug?
|
||||||
|
QTest::newRow("pure virtual declaration") << "defs.h" << 420 << ItemList{
|
||||||
|
makeItem(17, 17, Usage::Type::Declaration), makeItem(21, 9, Usage::Type::Declaration),
|
||||||
|
makeItem(21, 9, Usage::Type::Declaration)};
|
||||||
|
|
||||||
|
QTest::newRow("pointer variable") << "main.cpp" << 52 << ItemList{
|
||||||
|
makeItem(6, 10, Usage::Type::Initialization), makeItem(8, 4, Usage::Type::Write),
|
||||||
|
makeItem(10, 4, Usage::Type::Write), makeItem(24, 5, Usage::Type::Write),
|
||||||
|
makeItem(25, 11, Usage::Type::WritableRef), makeItem(26, 11, Usage::Type::Read),
|
||||||
|
makeItem(27, 10, Usage::Type::WritableRef), makeItem(28, 10, Usage::Type::Read),
|
||||||
|
makeItem(29, 11, Usage::Type::Read), makeItem(30, 15, Usage::Type::WritableRef),
|
||||||
|
makeItem(31, 22, Usage::Type::Read)};
|
||||||
|
QTest::newRow("struct variable") << "main.cpp" << 39 << ItemList{
|
||||||
|
makeItem(5, 7, Usage::Type::Declaration), makeItem(6, 15, Usage::Type::WritableRef),
|
||||||
|
makeItem(8, 9, Usage::Type::WritableRef), makeItem(9, 11, Usage::Type::WritableRef),
|
||||||
|
makeItem(11, 4, Usage::Type::Write), makeItem(11, 11, Usage::Type::WritableRef),
|
||||||
|
makeItem(12, 12, Usage::Type::WritableRef), makeItem(13, 6, Usage::Type::Write),
|
||||||
|
makeItem(14, 21, Usage::Type::Read), makeItem(15, 4, Usage::Type::Write),
|
||||||
|
makeItem(15, 12, Usage::Type::Read), makeItem(16, 22, Usage::Type::WritableRef),
|
||||||
|
makeItem(17, 13, Usage::Type::WritableRef), makeItem(18, 20, Usage::Type::Read),
|
||||||
|
makeItem(19, 10, Usage::Type::WritableRef), makeItem(20, 10, Usage::Type::Read),
|
||||||
|
makeItem(21, 11, Usage::Type::WritableRef), makeItem(22, 11, Usage::Type::Read),
|
||||||
|
makeItem(23, 10, Usage::Type::Read), makeItem(32, 4, Usage::Type::Write),
|
||||||
|
makeItem(33, 23, Usage::Type::WritableRef), makeItem(34, 23, Usage::Type::Read),
|
||||||
|
makeItem(35, 15, Usage::Type::WritableRef), makeItem(36, 22, Usage::Type::WritableRef),
|
||||||
|
makeItem(37, 4, Usage::Type::Read), makeItem(38, 4, Usage::Type::WritableRef),
|
||||||
|
makeItem(39, 6, Usage::Type::WritableRef), makeItem(40, 4, Usage::Type::Read),
|
||||||
|
makeItem(41, 4, Usage::Type::WritableRef), makeItem(42, 4, Usage::Type::Read),
|
||||||
|
makeItem(42, 18, Usage::Type::Read), makeItem(43, 11, Usage::Type::Write),
|
||||||
|
makeItem(54, 4, Usage::Type::Other), makeItem(55, 4, Usage::Type::Other)};
|
||||||
|
|
||||||
|
// Some of these are conceptually questionable, as S is a type and thus we cannot "read from"
|
||||||
|
// or "write to" it. But it probably matches the intuitive user expectation.
|
||||||
|
QTest::newRow("struct type") << "defs.h" << 7 << ItemList{
|
||||||
|
makeItem(1, 7, Usage::Type::Declaration), makeItem(2, 4, Usage::Type::Declaration),
|
||||||
|
makeItem(20, 19, Usage::Type::Other), makeItem(10, 9, Usage::Type::WritableRef),
|
||||||
|
makeItem(12, 4, Usage::Type::Write), makeItem(44, 12, Usage::Type::Read),
|
||||||
|
makeItem(45, 13, Usage::Type::Read), makeItem(47, 12, Usage::Type::Write),
|
||||||
|
makeItem(50, 8, Usage::Type::Read), makeItem(51, 8, Usage::Type::Write),
|
||||||
|
makeItem(52, 6, Usage::Type::Write), makeItem(53, 4, Usage::Type::Write),
|
||||||
|
makeItem(56, 4, Usage::Type::Write), makeItem(56, 22, Usage::Type::Other),
|
||||||
|
makeItem(58, 10, Usage::Type::Read), makeItem(58, 22, Usage::Type::Read),
|
||||||
|
makeItem(59, 4, Usage::Type::Write), makeItem(59, 21, Usage::Type::Read)};
|
||||||
|
|
||||||
|
QTest::newRow("subclass") << "defs.h" << 450 << ItemList{
|
||||||
|
makeItem(20, 7, Usage::Type::Declaration), makeItem(5, 4, Usage::Type::Other),
|
||||||
|
makeItem(13, 21, Usage::Type::Other), makeItem(32, 8, Usage::Type::Other)};
|
||||||
|
QTest::newRow("array variable") << "main.cpp" << 1134 << ItemList{
|
||||||
|
makeItem(57, 8, Usage::Type::Declaration), makeItem(58, 4, Usage::Type::Write),
|
||||||
|
makeItem(59, 15, Usage::Type::Read)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// The main point here is to test our access type categorization.
|
// The main point here is to test our access type categorization.
|
||||||
// We do not try to stress-test clangd's "Find References" functionality; such tests belong
|
// We do not try to stress-test clangd's "Find References" functionality; such tests belong
|
||||||
// into LLVM.
|
// into LLVM.
|
||||||
void ClangdTests::testFindReferences()
|
void ClangdTestFindReferences::test()
|
||||||
{
|
{
|
||||||
// Find suitable kit.
|
QFETCH(QString, fileName);
|
||||||
const QList<Kit *> allKits = KitManager::kits();
|
QFETCH(int, pos);
|
||||||
if (allKits.isEmpty())
|
QFETCH(QList<SearchResultItem>, expectedResults);
|
||||||
QSKIP("This test requires at least one kit to be present");
|
|
||||||
Kit * const kit = Utils::findOr(allKits, nullptr, [](const Kit *k) {
|
|
||||||
return k->isValid() && QtSupport::QtKitAspect::qtVersion(k);
|
|
||||||
});
|
|
||||||
if (!kit)
|
|
||||||
QSKIP("The test requires at least one valid kit with a valid Qt");
|
|
||||||
|
|
||||||
// Copy project out of qrc file, open it, and set up target.
|
TextEditor::TextDocument * const doc = document(fileName);
|
||||||
CppTools::Tests::TemporaryCopiedDir testDir(qrcPath("find-usages"));
|
QVERIFY(doc);
|
||||||
QVERIFY(testDir.isValid());
|
QTextCursor cursor(doc->document());
|
||||||
const auto openProjectResult = ProjectExplorerPlugin::openProject(
|
cursor.setPosition(pos);
|
||||||
testDir.absolutePath("find-usages.pro"));
|
client()->findUsages(doc, cursor, {});
|
||||||
QVERIFY2(openProjectResult, qPrintable(openProjectResult.errorMessage()));
|
QVERIFY(waitForSignalOrTimeout(client(), &ClangdClient::findUsagesDone, timeOutInMs()));
|
||||||
openProjectResult.project()->configureAsExampleProject(kit);
|
|
||||||
|
|
||||||
// Setting up the project should result in a clangd client being created.
|
QCOMPARE(m_actualResults.size(), expectedResults.size());
|
||||||
// Wait until that has happened.
|
for (int i = 0; i < m_actualResults.size(); ++i) {
|
||||||
const auto modelManagerSupport = ClangModelManagerSupport::instance();
|
const SearchResultItem &curActual = m_actualResults.at(i);
|
||||||
ClangdClient *client = modelManagerSupport->clientForProject(openProjectResult.project());
|
const SearchResultItem &curExpected = expectedResults.at(i);
|
||||||
if (!client) {
|
QCOMPARE(curActual.mainRange().begin.line, curExpected.mainRange().begin.line);
|
||||||
QVERIFY(waitForSignalOrTimeout(modelManagerSupport,
|
QCOMPARE(curActual.mainRange().begin.column, curExpected.mainRange().begin.column);
|
||||||
&ClangModelManagerSupport::createdClient, timeOutInMs()));
|
QCOMPARE(curActual.userData(), curExpected.userData());
|
||||||
client = modelManagerSupport->clientForProject(openProjectResult.project());
|
}
|
||||||
}
|
}
|
||||||
QVERIFY(client);
|
|
||||||
client->enableTesting();
|
|
||||||
|
|
||||||
// Wait until the client is fully initialized, i.e. it's completed the handshake
|
|
||||||
// with the server.
|
|
||||||
if (!client->reachable())
|
|
||||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::initialized, timeOutInMs()));
|
|
||||||
QVERIFY(client->reachable());
|
|
||||||
|
|
||||||
// The kind of AST support we need was introduced in LLVM 13.
|
ClangdTestFollowSymbol::ClangdTestFollowSymbol()
|
||||||
if (client->versionNumber() < QVersionNumber(13))
|
{
|
||||||
QSKIP("Find Usages test needs clang >= 13");
|
setProjectFileName("follow-symbol.pro");
|
||||||
|
setSourceFileNames({"main.cpp", "header.h"});
|
||||||
|
setMinimumVersion(12);
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for index to build.
|
void ClangdTestFollowSymbol::test_data()
|
||||||
if (!client->isFullyIndexed())
|
{
|
||||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::indexingFinished, timeOutInMs()));
|
QTest::addColumn<QString>("sourceFile");
|
||||||
QVERIFY(client->isFullyIndexed());
|
QTest::addColumn<int>("sourceLine");
|
||||||
|
QTest::addColumn<int>("sourceColumn");
|
||||||
|
QTest::addColumn<QString>("targetFile");
|
||||||
|
QTest::addColumn<int>("targetLine");
|
||||||
|
QTest::addColumn<int>("targetColumn");
|
||||||
|
|
||||||
// Open cpp documents.
|
QTest::newRow("on namespace") << "main.cpp" << 27 << 1 << "header.h" << 28 << 11;
|
||||||
struct EditorCloser {
|
QTest::newRow("class ref") << "main.cpp" << 27 << 9 << "header.h" << 34 << 7;
|
||||||
static void cleanup(IEditor *editor) { EditorManager::closeEditors({editor}); }
|
QTest::newRow("forward decl (same file)") << "header.h" << 32 << 7 << "header.h" << 34 << 7;
|
||||||
|
QTest::newRow("forward decl (different file") << "header.h" << 48 << 9 << "main.cpp" << 54 << 7;
|
||||||
|
QTest::newRow("class definition (same file)") << "header.h" << 34 << 7 << "header.h" << 32 << 7;
|
||||||
|
QTest::newRow("class definition (different file)") << "main.cpp" << 54 << 7
|
||||||
|
<< "header.h" << 48 << 7;
|
||||||
|
QTest::newRow("constructor decl") << "header.h" << 36 << 5 << "main.cpp" << 27 << 14;
|
||||||
|
QTest::newRow("constructor definition") << "main.cpp" << 27 << 14 << "header.h" << 36 << 5;
|
||||||
|
QTest::newRow("member ref") << "main.cpp" << 39 << 10 << "header.h" << 38 << 18;
|
||||||
|
QTest::newRow("union member ref") << "main.cpp" << 91 << 20 << "main.cpp" << 86 << 13;
|
||||||
|
QTest::newRow("member decl") << "header.h" << 38 << 18 << "header.h" << 38 << 18;
|
||||||
|
QTest::newRow("function ref") << "main.cpp" << 66 << 12 << "main.cpp" << 35 << 5;
|
||||||
|
QTest::newRow("member function ref") << "main.cpp" << 42 << 12 << "main.cpp" << 49 << 21;
|
||||||
|
QTest::newRow("function with no def ref") << "main.cpp" << 43 << 5 << "header.h" << 59 << 5;
|
||||||
|
QTest::newRow("function def") << "main.cpp" << 35 << 5 << "header.h" << 52 << 5;
|
||||||
|
QTest::newRow("member function def") << "main.cpp" << 49 << 21 << "header.h" << 43 << 9;
|
||||||
|
QTest::newRow("member function decl") << "header.h" << 43 << 9 << "main.cpp" << 49 << 21;
|
||||||
|
QTest::newRow("include") << "main.cpp" << 25 << 13 << "header.h" << 1 << 1;
|
||||||
|
QTest::newRow("local var") << "main.cpp" << 39 << 6 << "main.cpp" << 36 << 9;
|
||||||
|
QTest::newRow("alias") << "main.cpp" << 36 << 5 << "main.cpp" << 33 << 7;
|
||||||
|
QTest::newRow("static var") << "main.cpp" << 40 << 27 << "header.h" << 30 << 7;
|
||||||
|
QTest::newRow("member function ref (other class)") << "main.cpp" << 62 << 39
|
||||||
|
<< "cursor.cpp" << 104 << 22;
|
||||||
|
QTest::newRow("macro ref") << "main.cpp" << 66 << 43 << "header.h" << 27 << 9;
|
||||||
|
QTest::newRow("on namespace 2") << "main.cpp" << 27 << 3 << "header.h" << 28 << 11;
|
||||||
|
QTest::newRow("after namespace") << "main.cpp" << 27 << 7 << "header.h" << 28 << 11;
|
||||||
|
QTest::newRow("operator def") << "main.cpp" << 76 << 13 << "main.cpp" << 72 << 9;
|
||||||
|
QTest::newRow("operator def 2") << "main.cpp" << 80 << 15 << "main.cpp" << 73 << 10;
|
||||||
|
QTest::newRow("operator decl") << "main.cpp" << 72 << 12 << "main.cpp" << 76 << 10;
|
||||||
|
QTest::newRow("operator decl 2") << "main.cpp" << 73 << 12 << "main.cpp" << 80 << 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangdTestFollowSymbol::test()
|
||||||
|
{
|
||||||
|
QFETCH(QString, sourceFile);
|
||||||
|
QFETCH(int, sourceLine);
|
||||||
|
QFETCH(int, sourceColumn);
|
||||||
|
QFETCH(QString, targetFile);
|
||||||
|
QFETCH(int, targetLine);
|
||||||
|
QFETCH(int, targetColumn);
|
||||||
|
|
||||||
|
TextEditor::TextDocument * const doc = document(sourceFile);
|
||||||
|
QVERIFY(doc);
|
||||||
|
|
||||||
|
QTimer timer;
|
||||||
|
timer.setSingleShot(true);
|
||||||
|
QEventLoop loop;
|
||||||
|
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||||
|
Utils::Link actualLink;
|
||||||
|
const auto handler = [&actualLink, &loop](const Utils::Link &l) {
|
||||||
|
actualLink = l;
|
||||||
|
loop.quit();
|
||||||
};
|
};
|
||||||
const auto headerPath = Utils::FilePath::fromString(testDir.absolutePath("defs.h"));
|
QTextCursor cursor(doc->document());
|
||||||
QVERIFY2(headerPath.exists(), qPrintable(headerPath.toUserOutput()));
|
const int pos = Utils::Text::positionInText(doc->document(), sourceLine, sourceColumn);
|
||||||
QScopedPointer<IEditor, EditorCloser> headerEditor(EditorManager::openEditor(headerPath));
|
cursor.setPosition(pos);
|
||||||
QVERIFY(headerEditor);
|
client()->followSymbol(doc, cursor, nullptr, handler, true, false);
|
||||||
const auto headerDoc = qobject_cast<TextEditor::TextDocument *>(headerEditor->document());
|
timer.start(10000);
|
||||||
QVERIFY(headerDoc);
|
loop.exec();
|
||||||
QVERIFY(client->documentForFilePath(headerPath) == headerDoc);
|
QVERIFY(timer.isActive());
|
||||||
const auto cppFilePath = Utils::FilePath::fromString(testDir.absolutePath("main.cpp"));
|
timer.stop();
|
||||||
QVERIFY2(cppFilePath.exists(), qPrintable(cppFilePath.toUserOutput()));
|
|
||||||
QScopedPointer<IEditor, EditorCloser> cppFileEditor(EditorManager::openEditor(cppFilePath));
|
|
||||||
QVERIFY(cppFileEditor);
|
|
||||||
const auto cppDoc = qobject_cast<TextEditor::TextDocument *>(cppFileEditor->document());
|
|
||||||
QVERIFY(cppDoc);
|
|
||||||
QVERIFY(client->documentForFilePath(cppFilePath) == cppDoc);
|
|
||||||
|
|
||||||
// ... and we're ready to go.
|
QCOMPARE(actualLink.targetFilePath, filePath(targetFile));
|
||||||
QList<SearchResultItem> searchResults;
|
QEXPECT_FAIL("union member ref", "FIXME: clangd points to union", Abort);
|
||||||
connect(client, &ClangdClient::foundReferences, this,
|
QCOMPARE(actualLink.targetLine, targetLine);
|
||||||
[&searchResults](const QList<SearchResultItem> &results) {
|
QCOMPARE(actualLink.targetColumn + 1, targetColumn);
|
||||||
if (results.isEmpty())
|
|
||||||
return;
|
|
||||||
if (results.first().path().first().endsWith("defs.h"))
|
|
||||||
searchResults = results + searchResults; // Guarantee expected file order.
|
|
||||||
else
|
|
||||||
searchResults += results;
|
|
||||||
});
|
|
||||||
|
|
||||||
#define FIND_USAGES(doc, pos) do { \
|
|
||||||
QTextCursor cursor((doc)->document()); \
|
|
||||||
cursor.setPosition((pos)); \
|
|
||||||
searchResults.clear(); \
|
|
||||||
client->findUsages((doc), cursor, {}); \
|
|
||||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone, timeOutInMs())); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define EXPECT_RESULT(index, lne, col, type) \
|
|
||||||
QCOMPARE(searchResults.at(index).mainRange().begin.line, lne); \
|
|
||||||
QCOMPARE(searchResults.at(index).mainRange().begin.column, col); \
|
|
||||||
QCOMPARE(searchResults.at(index).userData().toInt(), int(type))
|
|
||||||
|
|
||||||
// All kinds of checks involving a struct member.
|
|
||||||
FIND_USAGES(headerDoc, 55);
|
|
||||||
QCOMPARE(searchResults.size(), 32);
|
|
||||||
EXPECT_RESULT(0, 2, 17, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(1, 3, 15, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(2, 6, 17, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(3, 8, 11, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(4, 9, 13, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(5, 10, 12, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(6, 11, 13, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(7, 12, 14, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(8, 13, 26, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(9, 14, 23, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(10, 15, 14, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(11, 16, 24, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(12, 17, 15, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(13, 18, 22, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(14, 19, 12, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(15, 20, 12, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(16, 21, 13, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(17, 22, 13, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(18, 23, 12, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(19, 42, 20, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(20, 44, 15, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(21, 47, 15, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(22, 50, 11, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(23, 51, 11, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(24, 52, 9, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(25, 53, 7, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(26, 56, 7, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(27, 56, 25, Usage::Type::Other);
|
|
||||||
EXPECT_RESULT(28, 58, 13, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(29, 58, 25, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(30, 59, 7, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(31, 59, 24, Usage::Type::Read);
|
|
||||||
|
|
||||||
// Detect constructor member initialization as a write access.
|
|
||||||
FIND_USAGES(headerDoc, 68);
|
|
||||||
QCOMPARE(searchResults.size(), 2);
|
|
||||||
EXPECT_RESULT(0, 2, 10, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(1, 4, 8, Usage::Type::Declaration);
|
|
||||||
|
|
||||||
// Detect direct member initialization.
|
|
||||||
FIND_USAGES(headerDoc, 101);
|
|
||||||
QCOMPARE(searchResults.size(), 2);
|
|
||||||
EXPECT_RESULT(0, 5, 21, Usage::Type::Initialization);
|
|
||||||
EXPECT_RESULT(1, 45, 16, Usage::Type::Read);
|
|
||||||
|
|
||||||
// Make sure that pure virtual declaration is not mistaken for an assignment.
|
|
||||||
FIND_USAGES(headerDoc, 420);
|
|
||||||
QCOMPARE(searchResults.size(), 3); // FIXME: The override gets reported twice. clang bug?
|
|
||||||
EXPECT_RESULT(0, 17, 17, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(1, 21, 9, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(2, 21, 9, Usage::Type::Declaration);
|
|
||||||
|
|
||||||
// References to pointer variable.
|
|
||||||
FIND_USAGES(cppDoc, 52);
|
|
||||||
QCOMPARE(searchResults.size(), 11);
|
|
||||||
EXPECT_RESULT(0, 6, 10, Usage::Type::Initialization);
|
|
||||||
EXPECT_RESULT(1, 8, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(2, 10, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(3, 24, 5, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(4, 25, 11, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(5, 26, 11, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(6, 27, 10, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(7, 28, 10, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(8, 29, 11, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(9, 30, 15, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(10, 31, 22, Usage::Type::Read);
|
|
||||||
|
|
||||||
// References to struct variable, directly and via members.
|
|
||||||
FIND_USAGES(cppDoc, 39);
|
|
||||||
QCOMPARE(searchResults.size(), 34);
|
|
||||||
EXPECT_RESULT(0, 5, 7, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(1, 6, 15, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(2, 8, 9, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(3, 9, 11, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(4, 11, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(5, 11, 11, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(6, 12, 12, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(7, 13, 6, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(8, 14, 21, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(9, 15, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(10, 15, 12, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(11, 16, 22, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(12, 17, 13, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(13, 18, 20, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(14, 19, 10, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(15, 20, 10, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(16, 21, 11, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(17, 22, 11, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(18, 23, 10, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(19, 32, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(20, 33, 23, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(21, 34, 23, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(22, 35, 15, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(23, 36, 22, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(24, 37, 4, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(25, 38, 4, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(26, 39, 6, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(27, 40, 4, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(28, 41, 4, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(29, 42, 4, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(30, 42, 18, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(31, 43, 11, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(32, 54, 4, Usage::Type::Other);
|
|
||||||
EXPECT_RESULT(33, 55, 4, Usage::Type::Other);
|
|
||||||
|
|
||||||
// References to struct type.
|
|
||||||
FIND_USAGES(headerDoc, 7);
|
|
||||||
QCOMPARE(searchResults.size(), 18);
|
|
||||||
EXPECT_RESULT(0, 1, 7, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(1, 2, 4, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(2, 20, 19, Usage::Type::Other);
|
|
||||||
|
|
||||||
// These are conceptually questionable, as S is a type and thus we cannot "read from"
|
|
||||||
// or "write to" it. But it probably matches the intuitive user expectation.
|
|
||||||
EXPECT_RESULT(3, 10, 9, Usage::Type::WritableRef);
|
|
||||||
EXPECT_RESULT(4, 12, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(5, 44, 12, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(6, 45, 13, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(7, 47, 12, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(8, 50, 8, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(9, 51, 8, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(10, 52, 6, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(11, 53, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(12, 56, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(13, 56, 22, Usage::Type::Other);
|
|
||||||
EXPECT_RESULT(14, 58, 10, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(15, 58, 22, Usage::Type::Read);
|
|
||||||
EXPECT_RESULT(16, 59, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(17, 59, 21, Usage::Type::Read);
|
|
||||||
|
|
||||||
// References to subclass type.
|
|
||||||
FIND_USAGES(headerDoc, 450);
|
|
||||||
QCOMPARE(searchResults.size(), 4);
|
|
||||||
EXPECT_RESULT(0, 20, 7, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(1, 5, 4, Usage::Type::Other);
|
|
||||||
EXPECT_RESULT(2, 13, 21, Usage::Type::Other);
|
|
||||||
EXPECT_RESULT(3, 32, 8, Usage::Type::Other);
|
|
||||||
|
|
||||||
// References to array variables.
|
|
||||||
FIND_USAGES(cppDoc, 1134);
|
|
||||||
QCOMPARE(searchResults.size(), 3);
|
|
||||||
EXPECT_RESULT(0, 57, 8, Usage::Type::Declaration);
|
|
||||||
EXPECT_RESULT(1, 58, 4, Usage::Type::Write);
|
|
||||||
EXPECT_RESULT(2, 59, 15, Usage::Type::Read);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Tests
|
} // namespace Tests
|
||||||
|
@@ -25,20 +25,83 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cpptools/cpptoolstestcase.h>
|
||||||
|
#include <coreplugin/find/searchresultitem.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace ProjectExplorer {
|
||||||
|
class Kit;
|
||||||
|
class Project;
|
||||||
|
}
|
||||||
|
namespace TextEditor { class TextDocument; }
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
class ClangdClient;
|
||||||
namespace Tests {
|
namespace Tests {
|
||||||
|
|
||||||
class ClangdTests : public QObject
|
class ClangdTest : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
~ClangdTest();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Convention: base bame == name of parent dir
|
||||||
|
void setProjectFileName(const QString &fileName) { m_projectFileName = fileName; }
|
||||||
|
|
||||||
|
void setSourceFileNames(const QStringList &fileNames) { m_sourceFileNames = fileNames; }
|
||||||
|
void setMinimumVersion(int version) { m_minVersion = version; }
|
||||||
|
|
||||||
|
ClangdClient *client() const { return m_client; }
|
||||||
|
Utils::FilePath filePath(const QString &fileName) const;
|
||||||
|
TextEditor::TextDocument *document(const QString &fileName) const {
|
||||||
|
return m_sourceDocuments.value(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void initTestCase();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CppTools::Tests::TemporaryCopiedDir *m_projectDir = nullptr;
|
||||||
|
QString m_projectFileName;
|
||||||
|
QStringList m_sourceFileNames;
|
||||||
|
QHash<QString, TextEditor::TextDocument *> m_sourceDocuments;
|
||||||
|
ProjectExplorer::Kit *m_kit = nullptr;
|
||||||
|
ProjectExplorer::Project *m_project = nullptr;
|
||||||
|
ClangdClient *m_client = nullptr;
|
||||||
|
int m_minVersion = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClangdTestFindReferences : public ClangdTest
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ClangdTestFindReferences();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void initTestCase();
|
void initTestCase() override;
|
||||||
|
void init() { m_actualResults.clear(); }
|
||||||
|
void test_data();
|
||||||
|
void test();
|
||||||
|
|
||||||
void testFindReferences();
|
private:
|
||||||
|
QList<Core::SearchResultItem> m_actualResults;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClangdTestFollowSymbol : public ClangdTest
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ClangdTestFollowSymbol();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void test_data();
|
||||||
|
void test();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Tests
|
} // namespace Tests
|
||||||
|
@@ -32,5 +32,10 @@
|
|||||||
<file>find-usages/defs.h</file>
|
<file>find-usages/defs.h</file>
|
||||||
<file>find-usages/main.cpp</file>
|
<file>find-usages/main.cpp</file>
|
||||||
<file>find-usages/find-usages.pro</file>
|
<file>find-usages/find-usages.pro</file>
|
||||||
|
<file>follow-symbol/cursor.cpp</file>
|
||||||
|
<file>follow-symbol/cursor.h</file>
|
||||||
|
<file>follow-symbol/follow-symbol.pro</file>
|
||||||
|
<file>follow-symbol/header.h</file>
|
||||||
|
<file>follow-symbol/main.cpp</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
147
src/plugins/clangcodemodel/test/data/follow-symbol/cursor.cpp
Normal file
147
src/plugins/clangcodemodel/test/data/follow-symbol/cursor.cpp
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#include "cursor.h"
|
||||||
|
|
||||||
|
void function(int x)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Namespace
|
||||||
|
{
|
||||||
|
SuperClass::SuperClass(int x) noexcept
|
||||||
|
: y(x)
|
||||||
|
{
|
||||||
|
int LocalVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SuperClass::Method()
|
||||||
|
{
|
||||||
|
Method();
|
||||||
|
AbstractVirtualMethod(y);
|
||||||
|
int LocalVariable;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SuperClass::VirtualMethod(int z)
|
||||||
|
{
|
||||||
|
AbstractVirtualMethod(z);
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SuperClass::ConstMethod() const
|
||||||
|
{
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SuperClass::StaticMethod()
|
||||||
|
{
|
||||||
|
using longint = long long int;
|
||||||
|
using lint = longint;
|
||||||
|
|
||||||
|
lint foo;
|
||||||
|
|
||||||
|
foo = 30;
|
||||||
|
|
||||||
|
const lint bar = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void TemplateFunction(T LocalVariableParameter)
|
||||||
|
{
|
||||||
|
T LocalVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
Namespace::SuperClass::operator int() const
|
||||||
|
{
|
||||||
|
int LocalVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Namespace::SuperClass::operator ++() const
|
||||||
|
{
|
||||||
|
int LocalVariable;
|
||||||
|
|
||||||
|
return LocalVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
Namespace::SuperClass::~SuperClass()
|
||||||
|
{
|
||||||
|
int LocalVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Struct::FinalVirtualMethod()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void f1(Struct *FindFunctionCaller)
|
||||||
|
{
|
||||||
|
FindFunctionCaller->FinalVirtualMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
void f2(){
|
||||||
|
Struct *s = new Struct;
|
||||||
|
|
||||||
|
f1(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void f3()
|
||||||
|
{
|
||||||
|
auto FindFunctionCaller = Struct();
|
||||||
|
|
||||||
|
FindFunctionCaller.FinalVirtualMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void f4()
|
||||||
|
{
|
||||||
|
Struct s;
|
||||||
|
|
||||||
|
auto *sPointer = &s;
|
||||||
|
auto sValue = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NonFinalStruct::function()
|
||||||
|
{
|
||||||
|
FinalVirtualMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputFunction(int &out, int in = 1, const int &in2=2, int *out2=nullptr);
|
||||||
|
void InputFunction(const int &value);
|
||||||
|
|
||||||
|
void f5()
|
||||||
|
{
|
||||||
|
int OutputValue;
|
||||||
|
int InputValue = 20;
|
||||||
|
|
||||||
|
OutputFunction(OutputValue);
|
||||||
|
InputFunction(InputValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgumentCountZero();
|
||||||
|
void ArgumentCountTwo(int one, const int &two);
|
||||||
|
void IntegerValue(int);
|
||||||
|
void LValueReference(int &);
|
||||||
|
void ConstLValueReference(const int &);
|
||||||
|
void PointerToConst(const int *);
|
||||||
|
void Pointer(int *);
|
||||||
|
void ConstantPointer(int *const);
|
||||||
|
void ConstIntegerValue(const int);
|
||||||
|
|
||||||
|
void NonFinalStruct::ProtectedMethodAccessSpecifier() {}
|
||||||
|
|
||||||
|
extern int ExternVarStorageClass;
|
||||||
|
|
||||||
|
static void StaticMethodStorageClass() {}
|
||||||
|
|
||||||
|
template<class T> const T &InvalidStorageClass(const T &type) { return type; }
|
||||||
|
|
||||||
|
namespace Outer {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
X, Y
|
||||||
|
};
|
||||||
|
}
|
44
src/plugins/clangcodemodel/test/data/follow-symbol/cursor.h
Normal file
44
src/plugins/clangcodemodel/test/data/follow-symbol/cursor.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace Namespace
|
||||||
|
{
|
||||||
|
class SuperClass;
|
||||||
|
/**
|
||||||
|
* A brief comment
|
||||||
|
*/
|
||||||
|
class SuperClass
|
||||||
|
{
|
||||||
|
SuperClass() = default;
|
||||||
|
SuperClass(int x) noexcept;
|
||||||
|
int Method();
|
||||||
|
virtual int VirtualMethod(int z);
|
||||||
|
virtual int AbstractVirtualMethod(int z) = 0;
|
||||||
|
bool ConstMethod() const;
|
||||||
|
static void StaticMethod();
|
||||||
|
operator int() const;
|
||||||
|
int operator ++() const;
|
||||||
|
~SuperClass();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct final
|
||||||
|
{
|
||||||
|
virtual void FinalVirtualMethod() final;
|
||||||
|
};
|
||||||
|
|
||||||
|
union Union
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NonFinalStruct
|
||||||
|
{
|
||||||
|
virtual void FinalVirtualMethod() final;
|
||||||
|
void function();
|
||||||
|
protected:
|
||||||
|
void ProtectedMethodAccessSpecifier();
|
||||||
|
};
|
@@ -0,0 +1,4 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
CONFIG -= qt
|
||||||
|
HEADERS = cursor.h header.h
|
||||||
|
SOURCES = cursor.cpp main.cpp
|
59
src/plugins/clangcodemodel/test/data/follow-symbol/header.h
Normal file
59
src/plugins/clangcodemodel/test/data/follow-symbol/header.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 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
|
||||||
|
|
||||||
|
#define TEST_DEFINE 1
|
||||||
|
namespace Fooish
|
||||||
|
{
|
||||||
|
float flvalue = 100.f;
|
||||||
|
|
||||||
|
class Bar;
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
public:
|
||||||
|
Bar();
|
||||||
|
|
||||||
|
volatile int member = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Barish
|
||||||
|
{
|
||||||
|
int foo(float p, int u);
|
||||||
|
int mem = 10;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class FooClass;
|
||||||
|
|
||||||
|
int foo(const float p, int u);
|
||||||
|
|
||||||
|
int foo();
|
||||||
|
|
||||||
|
int foo(float p, int u)
|
||||||
|
{
|
||||||
|
return foo() + p + u;
|
||||||
|
}
|
||||||
|
|
||||||
|
int foo(int x, float y);
|
95
src/plugins/clangcodemodel/test/data/follow-symbol/main.cpp
Normal file
95
src/plugins/clangcodemodel/test/data/follow-symbol/main.cpp
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 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 "header.h"
|
||||||
|
#include "cursor.h"
|
||||||
|
Fooish::Bar::Bar() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class X;
|
||||||
|
|
||||||
|
using YYY = Fooish::Bar;
|
||||||
|
|
||||||
|
int foo() {
|
||||||
|
YYY bar;
|
||||||
|
bar.member = 30;
|
||||||
|
Fooish::Barish barish;
|
||||||
|
bar.member++;
|
||||||
|
barish.mem = Fooish::flvalue;
|
||||||
|
|
||||||
|
barish.foo(1.f, 2);
|
||||||
|
foo(1, 2.f);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
X* x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Fooish::Barish::foo(float p, int u)
|
||||||
|
{
|
||||||
|
return ::foo() + p + u;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FooClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FooClass();
|
||||||
|
static int mememember;
|
||||||
|
};
|
||||||
|
|
||||||
|
FooClass::FooClass() {
|
||||||
|
NonFinalStruct nfStruct; nfStruct.function();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
union {
|
||||||
|
int i = 12;
|
||||||
|
void *something;
|
||||||
|
};
|
||||||
|
int func(bool b) {
|
||||||
|
if (b)
|
||||||
|
return i;
|
||||||
|
int i = 42;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
Reference in New Issue
Block a user