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 {
|
||||
new Tests::ClangCodeCompletionTest,
|
||||
new Tests::ClangdTests,
|
||||
new Tests::ClangdTestFindReferences,
|
||||
new Tests::ClangdTestFollowSymbol,
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@@ -897,7 +897,6 @@ void ClangdClient::followSymbol(
|
||||
void ClangdClient::Private::handleGotoDefinitionResult()
|
||||
{
|
||||
QTC_ASSERT(followSymbolData->defLink.hasValidTarget(), return);
|
||||
QTC_ASSERT(followSymbolData->cursorNode.isValid(), return);
|
||||
|
||||
qCDebug(clangdLog) << "handling go to definition result";
|
||||
|
||||
|
@@ -78,7 +78,7 @@ public:
|
||||
QString error;
|
||||
};
|
||||
|
||||
enum CompilationDbPurpose { Project, CodeModel };
|
||||
enum class CompilationDbPurpose { Project, CodeModel };
|
||||
GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo,
|
||||
CompilationDbPurpose purpose);
|
||||
|
||||
|
@@ -35,7 +35,6 @@
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <cpptools/cpptoolstestcase.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/find/searchresultitem.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
@@ -43,6 +42,7 @@
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QFileInfo>
|
||||
#include <QScopedPointer>
|
||||
#include <QTimer>
|
||||
#include <QtTest>
|
||||
@@ -56,7 +56,19 @@ namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
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 QString clangdFromEnv = qEnvironmentVariable("QTC_CLANGD");
|
||||
@@ -66,249 +78,284 @@ void ClangdTests::initTestCase()
|
||||
if (clangd.isEmpty() || !clangd.exists())
|
||||
QSKIP("clangd binary not found");
|
||||
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.
|
||||
// We do not try to stress-test clangd's "Find References" functionality; such tests belong
|
||||
// into LLVM.
|
||||
void ClangdTests::testFindReferences()
|
||||
void ClangdTestFindReferences::test()
|
||||
{
|
||||
// Find suitable kit.
|
||||
const QList<Kit *> allKits = KitManager::kits();
|
||||
if (allKits.isEmpty())
|
||||
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");
|
||||
QFETCH(QString, fileName);
|
||||
QFETCH(int, pos);
|
||||
QFETCH(QList<SearchResultItem>, expectedResults);
|
||||
|
||||
// Copy project out of qrc file, open it, and set up target.
|
||||
CppTools::Tests::TemporaryCopiedDir testDir(qrcPath("find-usages"));
|
||||
QVERIFY(testDir.isValid());
|
||||
const auto openProjectResult = ProjectExplorerPlugin::openProject(
|
||||
testDir.absolutePath("find-usages.pro"));
|
||||
QVERIFY2(openProjectResult, qPrintable(openProjectResult.errorMessage()));
|
||||
openProjectResult.project()->configureAsExampleProject(kit);
|
||||
TextEditor::TextDocument * const doc = document(fileName);
|
||||
QVERIFY(doc);
|
||||
QTextCursor cursor(doc->document());
|
||||
cursor.setPosition(pos);
|
||||
client()->findUsages(doc, cursor, {});
|
||||
QVERIFY(waitForSignalOrTimeout(client(), &ClangdClient::findUsagesDone, timeOutInMs()));
|
||||
|
||||
// Setting up the project should result in a clangd client being created.
|
||||
// Wait until that has happened.
|
||||
const auto modelManagerSupport = ClangModelManagerSupport::instance();
|
||||
ClangdClient *client = modelManagerSupport->clientForProject(openProjectResult.project());
|
||||
if (!client) {
|
||||
QVERIFY(waitForSignalOrTimeout(modelManagerSupport,
|
||||
&ClangModelManagerSupport::createdClient, timeOutInMs()));
|
||||
client = modelManagerSupport->clientForProject(openProjectResult.project());
|
||||
QCOMPARE(m_actualResults.size(), expectedResults.size());
|
||||
for (int i = 0; i < m_actualResults.size(); ++i) {
|
||||
const SearchResultItem &curActual = m_actualResults.at(i);
|
||||
const SearchResultItem &curExpected = expectedResults.at(i);
|
||||
QCOMPARE(curActual.mainRange().begin.line, curExpected.mainRange().begin.line);
|
||||
QCOMPARE(curActual.mainRange().begin.column, curExpected.mainRange().begin.column);
|
||||
QCOMPARE(curActual.userData(), curExpected.userData());
|
||||
}
|
||||
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.
|
||||
if (client->versionNumber() < QVersionNumber(13))
|
||||
QSKIP("Find Usages test needs clang >= 13");
|
||||
ClangdTestFollowSymbol::ClangdTestFollowSymbol()
|
||||
{
|
||||
setProjectFileName("follow-symbol.pro");
|
||||
setSourceFileNames({"main.cpp", "header.h"});
|
||||
setMinimumVersion(12);
|
||||
}
|
||||
|
||||
// Wait for index to build.
|
||||
if (!client->isFullyIndexed())
|
||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::indexingFinished, timeOutInMs()));
|
||||
QVERIFY(client->isFullyIndexed());
|
||||
void ClangdTestFollowSymbol::test_data()
|
||||
{
|
||||
QTest::addColumn<QString>("sourceFile");
|
||||
QTest::addColumn<int>("sourceLine");
|
||||
QTest::addColumn<int>("sourceColumn");
|
||||
QTest::addColumn<QString>("targetFile");
|
||||
QTest::addColumn<int>("targetLine");
|
||||
QTest::addColumn<int>("targetColumn");
|
||||
|
||||
// Open cpp documents.
|
||||
struct EditorCloser {
|
||||
static void cleanup(IEditor *editor) { EditorManager::closeEditors({editor}); }
|
||||
QTest::newRow("on namespace") << "main.cpp" << 27 << 1 << "header.h" << 28 << 11;
|
||||
QTest::newRow("class ref") << "main.cpp" << 27 << 9 << "header.h" << 34 << 7;
|
||||
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"));
|
||||
QVERIFY2(headerPath.exists(), qPrintable(headerPath.toUserOutput()));
|
||||
QScopedPointer<IEditor, EditorCloser> headerEditor(EditorManager::openEditor(headerPath));
|
||||
QVERIFY(headerEditor);
|
||||
const auto headerDoc = qobject_cast<TextEditor::TextDocument *>(headerEditor->document());
|
||||
QVERIFY(headerDoc);
|
||||
QVERIFY(client->documentForFilePath(headerPath) == headerDoc);
|
||||
const auto cppFilePath = Utils::FilePath::fromString(testDir.absolutePath("main.cpp"));
|
||||
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);
|
||||
QTextCursor cursor(doc->document());
|
||||
const int pos = Utils::Text::positionInText(doc->document(), sourceLine, sourceColumn);
|
||||
cursor.setPosition(pos);
|
||||
client()->followSymbol(doc, cursor, nullptr, handler, true, false);
|
||||
timer.start(10000);
|
||||
loop.exec();
|
||||
QVERIFY(timer.isActive());
|
||||
timer.stop();
|
||||
|
||||
// ... and we're ready to go.
|
||||
QList<SearchResultItem> searchResults;
|
||||
connect(client, &ClangdClient::foundReferences, this,
|
||||
[&searchResults](const QList<SearchResultItem> &results) {
|
||||
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);
|
||||
QCOMPARE(actualLink.targetFilePath, filePath(targetFile));
|
||||
QEXPECT_FAIL("union member ref", "FIXME: clangd points to union", Abort);
|
||||
QCOMPARE(actualLink.targetLine, targetLine);
|
||||
QCOMPARE(actualLink.targetColumn + 1, targetColumn);
|
||||
}
|
||||
|
||||
} // namespace Tests
|
||||
|
@@ -25,20 +25,83 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cpptools/cpptoolstestcase.h>
|
||||
#include <coreplugin/find/searchresultitem.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Kit;
|
||||
class Project;
|
||||
}
|
||||
namespace TextEditor { class TextDocument; }
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
class ClangdClient;
|
||||
namespace Tests {
|
||||
|
||||
class ClangdTests : public QObject
|
||||
class ClangdTest : public QObject
|
||||
{
|
||||
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:
|
||||
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
|
||||
|
@@ -32,5 +32,10 @@
|
||||
<file>find-usages/defs.h</file>
|
||||
<file>find-usages/main.cpp</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>
|
||||
</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