ClangCodeModel: Use clangd for local renaming

Change-Id: I1536265a8d46c9840e722bdfcb8638906d3f45cf
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2021-06-01 18:14:12 +02:00
parent ca09774181
commit 40181057cd
10 changed files with 461 additions and 8 deletions

View File

@@ -30,6 +30,7 @@
#include "../clangdclient.h"
#include "../clangmodelmanagersupport.h"
#include <clangsupport/sourcelocationscontainer.h>
#include <cplusplus/FindUsages.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h>
@@ -47,6 +48,8 @@
#include <QTimer>
#include <QtTest>
#include <tuple>
using namespace CPlusPlus;
using namespace Core;
using namespace CppTools::Tests;
@@ -119,8 +122,10 @@ void ClangdTest::initTestCase()
QSKIP("clangd is too old");
// Wait for index to build.
if (!m_client->isFullyIndexed())
QVERIFY(waitForSignalOrTimeout(m_client, &ClangdClient::indexingFinished, timeOutInMs()));
if (!m_client->isFullyIndexed()) {
QVERIFY(waitForSignalOrTimeout(m_client, &ClangdClient::indexingFinished,
clangdIndexingTimeout()));
}
QVERIFY(m_client->isFullyIndexed());
// Open cpp documents.
@@ -359,6 +364,127 @@ void ClangdTestFollowSymbol::test()
QCOMPARE(actualLink.targetColumn + 1, targetColumn);
}
ClangdTestLocalReferences::ClangdTestLocalReferences()
{
setProjectFileName("local-references.pro");
setSourceFileNames({"references.cpp"});
setMinimumVersion(13);
}
using Range = std::tuple<int, int, int>;
// We currently only support local variables, but if and when clangd implements
// the linkedEditingRange request, we can change the expected values for
// the file-scope test cases from empty ranges to the actual locations.
void ClangdTestLocalReferences::test_data()
{
QTest::addColumn<int>("sourceLine");
QTest::addColumn<int>("sourceColumn");
QTest::addColumn<QList<Range>>("expectedRanges");
QTest::newRow("cursor not on identifier") << 3 << 5 << QList<Range>();
QTest::newRow("local variable, one use") << 3 << 9 << QList<Range>{{3, 9, 3}};
QTest::newRow("local variable, two uses") << 10 << 9
<< QList<Range>{{10, 9, 3}, {11, 12, 3}};
QTest::newRow("class name") << 16 << 7 << QList<Range>()
/* QList<Range>{{16, 7, 3}, {19, 5, 3}} */;
QTest::newRow("namespace") << 24 << 11 << QList<Range>()
/* QList<Range>{{24, 11, 1}, {25, 11, 1}, {26, 1, 1}} */;
QTest::newRow("class name via using") << 30 << 21 << QList<Range>()
/* QList<Range>{{30, 21, 3}, {31, 10, 3}} */;
QTest::newRow("forward-declared class") << 35 << 7 << QList<Range>()
/* QList<Range>{{35, 7, 3}, {36, 14, 3}} */;
QTest::newRow("class name and new expression") << 40 << 7 << QList<Range>()
/* QList<Range>{{40, 7, 3}, {43, 9, 3}} */;
QTest::newRow("instantiated template object") << 52 << 19
<< QList<Range>{{52, 19, 3}, {53, 5, 3}};
QTest::newRow("variable in template") << 62 << 13 << QList<Range>()
/* QList<Range>{{62, 13, 3}, {63, 11, 3}} */;
QTest::newRow("member in template") << 67 << 7 << QList<Range>()
/* QList<Range>{{64, 16, 3}, {67, 7, 3}} */;
QTest::newRow("template type") << 58 << 19 << QList<Range>()
/* QList<Range>{{58, 19, 1}, {60, 5, 1}, {67, 5, 1}} */;
QTest::newRow("template parameter member access") << 76 << 9 << QList<Range>();
QTest::newRow("constructor as type") << 82 << 5 << QList<Range>()
/* QList<Range>{{81, 8, 3}, {82, 5, 3}, {83, 6, 3}} */;
QTest::newRow("freestanding overloads") << 88 << 5 << QList<Range>()
/* QList<Range>{{88, 5, 3}, {89, 5, 3}} */;
QTest::newRow("member function overloads") << 94 << 9 << QList<Range>()
/* QList<Range>{{94, 9, 3}, {95, 9, 3}} */;
QTest::newRow("function and function template") << 100 << 26 << QList<Range>()
/* QList<Range>{{100, 26, 3}, {101, 5, 3}} */;
QTest::newRow("function and function template as member") << 106 << 30 << QList<Range>()
/* QList<Range>{{106, 30, 3}, {107, 9, 3}} */;
QTest::newRow("enum type") << 112 << 6 << QList<Range>()
/* QList<Range>{{112, 6, 2}, {113, 8, 2}} */;
QTest::newRow("captured lambda var") << 122 << 15
<< QList<Range>{{122, 15, 3}, {122, 33, 3}};
QTest::newRow("lambda initializer") << 122 << 19
<< QList<Range>{{121, 19, 3}, {122, 19, 3}};
QTest::newRow("template specialization") << 127 << 25 << QList<Range>()
/* QList<Range>{{127, 5, 3}, {128, 25, 3}, {129, 18, 3}} */;
QTest::newRow("dependent name") << 133 << 34 << QList<Range>()
/* QList<Range>{{133, 34, 3} */;
QTest::newRow("function call and definition") << 140 << 5 << QList<Range>()
/* QList<Range>{{140, 5, 3}, {142, 25, 3}} */;
QTest::newRow("object-like macro") << 147 << 9 << QList<Range>()
/* QList<Range>{{147, 9, 3}, {150, 12, 3}} */;
QTest::newRow("function-like macro") << 155 << 9 << QList<Range>()
/* QList<Range>{{155, 9, 3}, {158, 12, 3}} */;
QTest::newRow("argument to function-like macro") << 156 << 27
<< QList<Range>{{156, 27, 3}, {158, 16, 3}};
QTest::newRow("overloaded bracket operator argument") << 172 << 7
<< QList<Range>{{171, 7, 1}, {172, 7, 1}, {172, 12, 1},
{173, 7, 1}, {173, 10, 1}};
QTest::newRow("overloaded call operator second argument") << 173 << 10
<< QList<Range>{{171, 7, 1}, {172, 7, 1}, {172, 12, 1},
{173, 7, 1}, {173, 10, 1}};
QTest::newRow("overloaded operators arguments from outside") << 171 << 7
<< QList<Range>{{171, 7, 1}, {172, 7, 1}, {172, 12, 1},
{173, 7, 1}, {173, 10, 1}};
}
void ClangdTestLocalReferences::test()
{
QFETCH(int, sourceLine);
QFETCH(int, sourceColumn);
QFETCH(QList<Range>, expectedRanges);
TextEditor::TextDocument * const doc = document("references.cpp");
QVERIFY(doc);
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
QList<Range> actualRanges;
const auto handler = [&actualRanges, &loop](const QString &symbol,
const ClangBackEnd::SourceLocationsContainer &container, int) {
for (const ClangBackEnd::SourceLocationContainer &c
: container.m_sourceLocationContainers) {
actualRanges << Range(c.line, c.column, symbol.length());
}
loop.quit();
};
QTextCursor cursor(doc->document());
const int pos = Utils::Text::positionInText(doc->document(), sourceLine, sourceColumn);
cursor.setPosition(pos);
client()->findLocalUsages(doc, cursor, std::move(handler));
timer.start(10000);
loop.exec();
QEXPECT_FAIL("cursor not on identifier", "clangd bug: go to definition does not return", Abort);
QEXPECT_FAIL("template parameter member access",
"clangd bug: go to definition does not return", Abort);
QVERIFY(timer.isActive());
timer.stop();
QCOMPARE(actualRanges, expectedRanges);
}
} // namespace Tests
} // namespace Internal
} // namespace ClangCodeModel
Q_DECLARE_METATYPE(ClangCodeModel::Internal::Tests::Range)