forked from qt-creator/qt-creator
Clang: Provide highlighting for identifier under cursor
Change-Id: I80ffe23cbcc84ab7323124581d9dd6afbe974fd0 Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -41,6 +41,9 @@
|
||||
#include <cmbregistertranslationunitsforeditormessage.h>
|
||||
#include <cmbunregisterprojectsforeditormessage.h>
|
||||
#include <cmbunregistertranslationunitsforeditormessage.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
@@ -128,6 +131,7 @@ protected:
|
||||
void updateVisibilty(const Utf8String ¤tEditor, const Utf8String &additionalVisibleEditor);
|
||||
|
||||
void requestDocumentAnnotations(const Utf8String &filePath);
|
||||
void requestReferences(quint32 documentRevision = 0);
|
||||
|
||||
void completeCode(const Utf8String &filePath, uint line = 1, uint column = 1,
|
||||
const Utf8String &projectPartId = Utf8String());
|
||||
@@ -136,6 +140,8 @@ protected:
|
||||
|
||||
bool isSupportiveTranslationUnitInitialized(const Utf8String &filePath);
|
||||
|
||||
DocumentProcessor documentProcessorForFile(const Utf8String &filePath);
|
||||
|
||||
void expectDocumentAnnotationsChanged(int count);
|
||||
void expectCompletion(const CodeCompletion &completion);
|
||||
void expectCompletionFromFileA();
|
||||
@@ -143,6 +149,7 @@ protected:
|
||||
void expectCompletionFromFileAUnsavedMethodVersion1();
|
||||
void expectCompletionFromFileAUnsavedMethodVersion2();
|
||||
void expectNoCompletionWithUnsavedMethod();
|
||||
void expectReferences();
|
||||
void expectDocumentAnnotationsChangedForFileBWithSpecificHighlightingMark();
|
||||
|
||||
static const Utf8String unsavedContent(const QString &unsavedFilePath);
|
||||
@@ -160,6 +167,7 @@ protected:
|
||||
= QStringLiteral(TESTDATA_DIR) + QStringLiteral("/complete_extractor_function_unsaved_2.cpp");
|
||||
|
||||
const Utf8String filePathB = Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp");
|
||||
const Utf8String filePathC = Utf8StringLiteral(TESTDATA_DIR"/references.cpp");
|
||||
|
||||
const Utf8String aFilePath = Utf8StringLiteral("afile.cpp");
|
||||
const Utf8String anExistingFilePath
|
||||
@@ -185,6 +193,25 @@ TEST_F(ClangCodeModelServerSlowTest, RequestDocumentAnnotations)
|
||||
requestDocumentAnnotations(filePathB);
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, RequestReferencesForCurrentDocumentRevision)
|
||||
{
|
||||
registerProjectAndFileAndWaitForFinished(filePathC);
|
||||
|
||||
expectReferences();
|
||||
requestReferences();
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, RequestReferencesTakesRevisionFromMessage)
|
||||
{
|
||||
registerProjectAndFileAndWaitForFinished(filePathC);
|
||||
|
||||
requestReferences(/*documentRevision=*/ 99);
|
||||
|
||||
JobRequests &queue = documentProcessorForFile(filePathC).queue();
|
||||
Utils::anyOf(queue, [](const JobRequest &request) { return request.documentRevision == 99; });
|
||||
queue.clear(); // Avoid blocking
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, NoInitialDocumentAnnotationsForClosedDocument)
|
||||
{
|
||||
const int expectedDocumentAnnotationsChangedCount = 0;
|
||||
@@ -462,7 +489,15 @@ bool ClangCodeModelServer::isSupportiveTranslationUnitInitialized(const Utf8Stri
|
||||
|
||||
return document.translationUnits().size() == 2
|
||||
&& documentProcessor.hasSupportiveTranslationUnit()
|
||||
&& documentProcessor.isSupportiveTranslationUnitInitialized();
|
||||
&& documentProcessor.isSupportiveTranslationUnitInitialized();
|
||||
}
|
||||
|
||||
DocumentProcessor ClangCodeModelServer::documentProcessorForFile(const Utf8String &filePath)
|
||||
{
|
||||
Document document = clangServer.documentsForTestOnly().document(filePath, projectPartId);
|
||||
DocumentProcessor documentProcessor = clangServer.documentProcessors().processor(document);
|
||||
|
||||
return documentProcessor;
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectCompletion(const CodeCompletion &completion)
|
||||
@@ -512,6 +547,20 @@ void ClangCodeModelServer::expectNoCompletionWithUnsavedMethod()
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectReferences()
|
||||
{
|
||||
const QVector<ClangBackEnd::SourceRangeContainer> references{{
|
||||
{filePathC, 3, 9},
|
||||
{filePathC, 3, 12}
|
||||
}};
|
||||
|
||||
EXPECT_CALL(mockClangCodeModelClient,
|
||||
references(
|
||||
Property(&ReferencesMessage::references,
|
||||
Eq(references))))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectCompletionFromFileA()
|
||||
{
|
||||
const CodeCompletion completion(Utf8StringLiteral("Function"),
|
||||
@@ -528,6 +577,15 @@ void ClangCodeModelServer::requestDocumentAnnotations(const Utf8String &filePath
|
||||
clangServer.requestDocumentAnnotations(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::requestReferences(quint32 documentRevision)
|
||||
{
|
||||
const FileContainer fileContainer{filePathC, projectPartId, Utf8StringVector(),
|
||||
documentRevision};
|
||||
const RequestReferencesMessage message{fileContainer, 3, 9};
|
||||
|
||||
clangServer.requestReferences(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectDocumentAnnotationsChangedForFileBWithSpecificHighlightingMark()
|
||||
{
|
||||
HighlightingTypes types;
|
||||
|
||||
@@ -65,6 +65,9 @@ protected:
|
||||
JobRequest::Type type,
|
||||
PreferredTranslationUnit preferredTranslationUnit
|
||||
= PreferredTranslationUnit::RecentlyParsed) const;
|
||||
JobRequest createJobRequestWithConditions(const Utf8String &filePath,
|
||||
JobRequest::Type type,
|
||||
JobRequest::Conditions conditions) const;
|
||||
|
||||
void updateDocumentRevision();
|
||||
void updateUnsavedFiles();
|
||||
@@ -410,6 +413,30 @@ TEST_F(JobQueue, RequestCompleteCodeOutdatableByDocumentRevisionChange)
|
||||
ASSERT_THAT(jobsToStart.size(), Eq(0));
|
||||
}
|
||||
|
||||
TEST_F(JobQueue, RequestReferencesRunsForCurrentDocumentRevision)
|
||||
{
|
||||
jobQueue.add( createJobRequestWithConditions(filePath1,
|
||||
JobRequest::Type::RequestReferences,
|
||||
JobRequest::Condition::CurrentDocumentRevision));
|
||||
|
||||
const JobRequests jobsToStart = jobQueue.processQueue();
|
||||
|
||||
ASSERT_THAT(jobsToStart.size(), Eq(1));
|
||||
}
|
||||
|
||||
TEST_F(JobQueue, RequestReferencesOutdatableByDocumentClose)
|
||||
{
|
||||
jobQueue.add(createJobRequestWithConditions(filePath1,
|
||||
JobRequest::Type::RequestReferences,
|
||||
JobRequest::Condition::CurrentDocumentRevision));
|
||||
removeDocument();
|
||||
|
||||
const JobRequests jobsToStart = jobQueue.processQueue();
|
||||
|
||||
ASSERT_THAT(jobsToStart.size(), Eq(0));
|
||||
ASSERT_THAT(jobQueue.size(), Eq(0));
|
||||
}
|
||||
|
||||
void JobQueue::SetUp()
|
||||
{
|
||||
projects.createOrUpdate({ProjectPartContainer(projectPartId)});
|
||||
@@ -460,6 +487,18 @@ JobRequest JobQueue::createJobRequest(
|
||||
return jobRequest;
|
||||
}
|
||||
|
||||
JobRequest JobQueue::createJobRequestWithConditions(const Utf8String &filePath,
|
||||
JobRequest::Type type,
|
||||
JobRequest::Conditions conditions) const
|
||||
{
|
||||
JobRequest jobRequest = createJobRequest(filePath,
|
||||
type,
|
||||
PreferredTranslationUnit::RecentlyParsed);
|
||||
jobRequest.conditions = conditions;
|
||||
|
||||
return jobRequest;
|
||||
}
|
||||
|
||||
void JobQueue::updateDocumentRevision()
|
||||
{
|
||||
documents.update({FileContainer(filePath1, projectPartId, Utf8String(), true, 1)});
|
||||
|
||||
@@ -56,7 +56,7 @@ protected:
|
||||
void TearDown() override;
|
||||
|
||||
bool waitUntilAllJobsFinished(int timeOutInMs = 10000) const;
|
||||
bool waitUntilJobChainFinished(int timeOutInMs = 10000) const;
|
||||
bool waitUntilJobChainFinished(int timeOutInMs = 10000);
|
||||
|
||||
protected:
|
||||
ClangBackEnd::ProjectParts projects;
|
||||
@@ -134,7 +134,7 @@ bool Jobs::waitUntilAllJobsFinished(int timeOutInMs) const
|
||||
return ProcessEventUtilities::processEventsUntilTrue(noJobsRunningAnymore, timeOutInMs);
|
||||
}
|
||||
|
||||
bool Jobs::waitUntilJobChainFinished(int timeOutInMs) const
|
||||
bool Jobs::waitUntilJobChainFinished(int timeOutInMs)
|
||||
{
|
||||
const auto noJobsRunningAnymore = [this]() {
|
||||
return jobs.runningJobs().isEmpty() && jobs.queue().isEmpty();
|
||||
|
||||
479
tests/unit/unittest/clangreferencescollector-test.cpp
Normal file
479
tests/unit/unittest/clangreferencescollector-test.cpp
Normal file
@@ -0,0 +1,479 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include <clangbackendipc_global.h>
|
||||
#include <clangreferencescollector.h>
|
||||
#include <clangdocument.h>
|
||||
#include <clangdocuments.h>
|
||||
#include <clangtranslationunit.h>
|
||||
#include <fixitcontainer.h>
|
||||
#include <projectpart.h>
|
||||
#include <projects.h>
|
||||
#include <sourcelocationcontainer.h>
|
||||
#include <sourcerangecontainer.h>
|
||||
#include <unsavedfiles.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
using ::testing::Contains;
|
||||
using ::testing::Not;
|
||||
using ::testing::ContainerEq;
|
||||
using ::testing::Eq;
|
||||
|
||||
using ::ClangBackEnd::ProjectPart;
|
||||
using ::ClangBackEnd::SourceLocationContainer;
|
||||
using ::ClangBackEnd::Document;
|
||||
using ::ClangBackEnd::UnsavedFiles;
|
||||
using ::ClangBackEnd::ReferencesResult;
|
||||
using ::ClangBackEnd::SourceRangeContainer;
|
||||
|
||||
using References = QVector<SourceRangeContainer>;
|
||||
|
||||
namespace {
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ReferencesResult &value)
|
||||
{
|
||||
os << "ReferencesResult(";
|
||||
os << value.isLocalVariable << ", {";
|
||||
for (const SourceRangeContainer &r : value.references) {
|
||||
os << r.start().line() << ",";
|
||||
os << r.start().column() << ",";
|
||||
QTC_CHECK(r.start().line() == r.end().line());
|
||||
os << r.end().column() - r.start().column() << ",";
|
||||
}
|
||||
os << "})";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
struct Data {
|
||||
Data()
|
||||
{
|
||||
document.parse();
|
||||
}
|
||||
|
||||
ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++14")}};
|
||||
ClangBackEnd::ProjectParts projects;
|
||||
ClangBackEnd::UnsavedFiles unsavedFiles;
|
||||
ClangBackEnd::Documents documents{projects, unsavedFiles};
|
||||
Document document{Utf8StringLiteral(TESTDATA_DIR"/references.cpp"),
|
||||
projectPart,
|
||||
Utf8StringVector(),
|
||||
documents};
|
||||
};
|
||||
|
||||
class ReferencesCollector : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
ReferencesResult getReferences(uint line, uint column)
|
||||
{
|
||||
return d->document.translationUnit().references(line, column);
|
||||
}
|
||||
|
||||
SourceLocationContainer createSourceLocation(uint line, uint column) const
|
||||
{
|
||||
return SourceLocationContainer(d->document.filePath(), line, column);
|
||||
}
|
||||
|
||||
SourceRangeContainer createSourceRange(uint line, uint column, uint length) const
|
||||
{
|
||||
return SourceRangeContainer {
|
||||
createSourceLocation(line, column),
|
||||
createSourceLocation(line, column + length)
|
||||
};
|
||||
}
|
||||
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
private:
|
||||
static std::unique_ptr<Data> d;
|
||||
};
|
||||
|
||||
// This test is not strictly needed as the plugin is supposed to put the cursor
|
||||
// on the identifier start.
|
||||
TEST_F(ReferencesCollector, CursorNotOnIdentifier)
|
||||
{
|
||||
const ReferencesResult expected { false, {}, };
|
||||
|
||||
const ReferencesResult actual = getReferences(3, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, LocalVariableWithSingleUse)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(3, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(3, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, LocalVariableWithTwoUses)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(10, 9, 3),
|
||||
createSourceRange(11, 12, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(10, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassName)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(16, 7, 3),
|
||||
createSourceRange(19, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(16, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, Namespace)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(24, 11, 1),
|
||||
createSourceRange(25, 11, 1),
|
||||
createSourceRange(26, 1, 1)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(24, 11);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassNameDeclaredWithUsing)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(30, 21, 3),
|
||||
createSourceRange(31, 10, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(30, 21);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassNameForwardDeclared)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(35, 7, 3),
|
||||
createSourceRange(36, 14, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(35, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassNameAndNewExpression)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(40, 7, 3),
|
||||
createSourceRange(43, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(40, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, InstantiatedTemplateObject)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(52, 19, 3),
|
||||
createSourceRange(53, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(52, 19);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, VariableInTemplate)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(62, 13, 3),
|
||||
createSourceRange(63, 11, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(62, 13);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, MemberInTemplate)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(64, 16, 3),
|
||||
createSourceRange(67, 7, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(67, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, TemplateType)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(58, 19, 1),
|
||||
createSourceRange(60, 5, 1),
|
||||
createSourceRange(67, 5, 1)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(58, 19);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, MemberAccessIntoTemplateParameter)
|
||||
{
|
||||
const ReferencesResult expected { false, {}, };
|
||||
|
||||
const ReferencesResult actual = getReferences(76, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ConstructorAsType)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(81, 8, 3),
|
||||
createSourceRange(82, 5, 3),
|
||||
createSourceRange(83, 6, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(82, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, OverloadsFreeStanding)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(88, 5, 3),
|
||||
createSourceRange(89, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(88, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, OverloadsMemberFunctions)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(94, 9, 3),
|
||||
createSourceRange(95, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(94, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionAndTemplateFunction)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(100, 26, 3),
|
||||
createSourceRange(101, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(100, 26);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionAndTemplateFunctionAsMember)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(106, 30, 3),
|
||||
createSourceRange(107, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(106, 30);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, EnumType)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(112, 6, 2),
|
||||
createSourceRange(113, 8, 2)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(112, 6);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, LambdaCapturedObject)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(122, 15, 3),
|
||||
createSourceRange(122, 33, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(122, 15);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
//// Disabled because it looks like the lambda initializer is not yet exposed by libclang.
|
||||
TEST_F(ReferencesCollector, DISABLED_LambdaCaptureInitializer)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(121, 19, 3),
|
||||
createSourceRange(122, 19, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(122, 19);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, TemplateSpecialization)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(127, 25, 3),
|
||||
createSourceRange(128, 25, 3),
|
||||
createSourceRange(129, 18, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(127, 25);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, TemplateDependentName)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(133, 34, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(133, 34);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionCallAndDefinition)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(140, 5, 3),
|
||||
createSourceRange(142, 25, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(140, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ObjectLikeMacro)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(147, 9, 3),
|
||||
createSourceRange(150, 12, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(147, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionLikeMacro)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(155, 9, 3),
|
||||
createSourceRange(158, 12, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(155, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ArgumentToFunctionLikeMacro)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(156, 27, 3),
|
||||
createSourceRange(158, 16, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(156, 27);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
std::unique_ptr<Data> ReferencesCollector::d;
|
||||
|
||||
void ReferencesCollector::SetUpTestCase()
|
||||
{
|
||||
d.reset(new Data);
|
||||
}
|
||||
|
||||
void ReferencesCollector::TearDownTestCase()
|
||||
{
|
||||
d.reset();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
114
tests/unit/unittest/clangrequestreferencesjob-test.cpp
Normal file
114
tests/unit/unittest/clangrequestreferencesjob-test.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangasyncjob-base.h"
|
||||
|
||||
#include <clangrequestreferencesjob.h>
|
||||
|
||||
using namespace ClangBackEnd;
|
||||
|
||||
using testing::_;
|
||||
using testing::Eq;
|
||||
using testing::Property;
|
||||
|
||||
namespace {
|
||||
|
||||
class RequestReferencesJob : public ClangAsyncJobTest
|
||||
{
|
||||
protected:
|
||||
void SetUp() override { BaseSetUp(JobRequest::Type::RequestReferences, job); }
|
||||
|
||||
protected:
|
||||
ClangBackEnd::RequestReferencesJob job;
|
||||
};
|
||||
|
||||
TEST_F(RequestReferencesJob, PrepareAsyncRun)
|
||||
{
|
||||
job.setContext(jobContext);
|
||||
|
||||
ASSERT_TRUE(job.prepareAsyncRun());
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, RunAsync)
|
||||
{
|
||||
job.setContext(jobContext);
|
||||
job.prepareAsyncRun();
|
||||
|
||||
job.runAsync();
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, SendReferences)
|
||||
{
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient, references(_)).Times(1);
|
||||
|
||||
job.runAsync();
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, ForwardTicketNumber)
|
||||
{
|
||||
jobRequest.ticketNumber = static_cast<quint64>(99);
|
||||
jobContextWithMockClient = JobContext(jobRequest, &documents, &unsavedFiles, &mockIpcClient);
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient,
|
||||
references(Property(&ReferencesMessage::ticketNumber, Eq(99))))
|
||||
.Times(1);
|
||||
|
||||
job.runAsync();
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, DontSendReferencesIfDocumentWasClosed)
|
||||
{
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient, references(_)).Times(0);
|
||||
|
||||
job.runAsync();
|
||||
documents.remove({FileContainer{filePath, projectPartId}});
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, DontSendReferencesIfDocumentRevisionChanged)
|
||||
{
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient, references(_)).Times(0);
|
||||
|
||||
job.runAsync();
|
||||
documents.update({FileContainer(filePath, projectPartId, Utf8String(), true, 99)});
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <readmessageblock.h>
|
||||
#include <registerunsavedfilesforeditormessage.h>
|
||||
#include <requestdocumentannotations.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
#include <translationunitdoesnotexistmessage.h>
|
||||
#include <unregisterunsavedfilesforeditormessage.h>
|
||||
#include <updatetranslationunitsforeditormessage.h>
|
||||
|
||||
159
tests/unit/unittest/data/references.cpp
Normal file
159
tests/unit/unittest/data/references.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
void variableSingleReference()
|
||||
{
|
||||
int foo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int variableMultipleReferences()
|
||||
{
|
||||
int foo = 0;
|
||||
return foo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Foo {};
|
||||
void bla()
|
||||
{
|
||||
Foo foo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace N { class Bar {}; }
|
||||
namespace N { class Baz {}; }
|
||||
N::Bar bar;
|
||||
|
||||
|
||||
|
||||
namespace G { class App {}; }
|
||||
using G::App;
|
||||
|
||||
|
||||
|
||||
class Hoo;
|
||||
void f(const Hoo &);
|
||||
|
||||
|
||||
|
||||
class Moo {};
|
||||
void x()
|
||||
{
|
||||
new Moo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Element {};
|
||||
template<typename T> struct Wrap { T member; };
|
||||
void g()
|
||||
{
|
||||
Wrap<Element> con;
|
||||
con.member;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Wrapper {
|
||||
T f()
|
||||
{
|
||||
int foo;
|
||||
++foo;
|
||||
return mem;
|
||||
}
|
||||
|
||||
T mem;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
void f()
|
||||
{
|
||||
T mem;
|
||||
mem.foo();
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Woo {
|
||||
Woo();
|
||||
~Woo();
|
||||
};
|
||||
|
||||
|
||||
|
||||
int muu();
|
||||
int muu(int);
|
||||
|
||||
|
||||
|
||||
struct Doo {
|
||||
int muu();
|
||||
int muu(int);
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T> int tuu();
|
||||
int tuu(int);
|
||||
|
||||
|
||||
|
||||
struct Xoo {
|
||||
template<typename T> int tuu();
|
||||
int tuu(int);
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum ET { E1 };
|
||||
bool e(ET e)
|
||||
{
|
||||
return e == E1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct LData { int member; };
|
||||
void lambda(LData foo) {
|
||||
auto l = [bar=foo] { return bar.member; };
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T> class Coo;
|
||||
template<class T> class Coo<T*>;
|
||||
template<> class Coo<int>;
|
||||
|
||||
|
||||
|
||||
template<typename T> typename T::foo n()
|
||||
{
|
||||
typename T::bla hello;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rec(int n = 100)
|
||||
{
|
||||
return n == 0 ? 0 : rec(--n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FOO 3
|
||||
int objectLikeMacro()
|
||||
{
|
||||
return FOO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define BAR(x) x
|
||||
int functionLikeMacro(int foo)
|
||||
{
|
||||
return BAR(foo);
|
||||
}
|
||||
@@ -38,4 +38,5 @@ public:
|
||||
void translationUnitDoesNotExist(const ClangBackEnd::TranslationUnitDoesNotExistMessage &) override {}
|
||||
void projectPartsDoNotExist(const ClangBackEnd::ProjectPartsDoNotExistMessage &) override {}
|
||||
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &) override {}
|
||||
void references(const ClangBackEnd::ReferencesMessage &) override {}
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <clangbackendipc/cmbcodecompletedmessage.h>
|
||||
#include <clangbackendipc/cmbechomessage.h>
|
||||
#include <clangbackendipc/documentannotationschangedmessage.h>
|
||||
#include <clangbackendipc/referencesmessage.h>
|
||||
#include <clangbackendipc/projectpartsdonotexistmessage.h>
|
||||
#include <clangbackendipc/translationunitdoesnotexistmessage.h>
|
||||
#include <clangbackendipc/updatetranslationunitsforeditormessage.h>
|
||||
@@ -51,4 +52,6 @@ public:
|
||||
void(const ClangBackEnd::ProjectPartsDoNotExistMessage &message));
|
||||
MOCK_METHOD1(documentAnnotationsChanged,
|
||||
void(const ClangBackEnd::DocumentAnnotationsChangedMessage &message));
|
||||
MOCK_METHOD1(references,
|
||||
void(const ClangBackEnd::ReferencesMessage &message));
|
||||
};
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
void(const ClangBackEnd::CompleteCodeMessage &message));
|
||||
MOCK_METHOD1(requestDocumentAnnotations,
|
||||
void(const ClangBackEnd::RequestDocumentAnnotationsMessage &message));
|
||||
MOCK_METHOD1(requestReferences,
|
||||
void(const ClangBackEnd::RequestReferencesMessage &message));
|
||||
MOCK_METHOD1(updateVisibleTranslationUnits,
|
||||
void(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message));
|
||||
};
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <highlightingmarkcontainer.h>
|
||||
#include <messageenvelop.h>
|
||||
#include <requestdocumentannotations.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
#include <referencesmessage.h>
|
||||
#include <readmessageblock.h>
|
||||
#include <registerunsavedfilesforeditormessage.h>
|
||||
#include <unregisterunsavedfilesforeditormessage.h>
|
||||
@@ -206,6 +208,21 @@ TEST_F(ReadAndWriteMessageBlock, CompareRequestDocumentAnnotations)
|
||||
CompareMessage(ClangBackEnd::RequestDocumentAnnotationsMessage(fileContainer));
|
||||
}
|
||||
|
||||
TEST_F(ReadAndWriteMessageBlock, CompareRequestReferences)
|
||||
{
|
||||
CompareMessage(ClangBackEnd::RequestReferencesMessage{fileContainer, 13, 37});
|
||||
}
|
||||
|
||||
TEST_F(ReadAndWriteMessageBlock, CompareReferences)
|
||||
{
|
||||
const QVector<ClangBackEnd::SourceRangeContainer> references{
|
||||
true,
|
||||
{{fileContainer.filePath(), 12, 34},
|
||||
{fileContainer.filePath(), 56, 78}}
|
||||
};
|
||||
CompareMessage(ClangBackEnd::ReferencesMessage(fileContainer, references, true, 1));
|
||||
}
|
||||
|
||||
TEST_F(ReadAndWriteMessageBlock, GetInvalidMessageForAPartialBuffer)
|
||||
{
|
||||
writeCodeCompletedMessage();
|
||||
|
||||
@@ -85,6 +85,8 @@ SOURCES += \
|
||||
clangjobqueue-test.cpp \
|
||||
clangjobs-test.cpp \
|
||||
clangrequestdocumentannotationsjob-test.cpp \
|
||||
clangrequestreferencesjob-test.cpp \
|
||||
clangreferencescollector-test.cpp \
|
||||
clangstring-test.cpp \
|
||||
clangtranslationunit-test.cpp \
|
||||
clangtranslationunits-test.cpp \
|
||||
|
||||
Reference in New Issue
Block a user