diff options
author | Ivan Donchevskii <ivan.donchevskii@qt.io> | 2017-07-28 09:48:13 +0200 |
---|---|---|
committer | Ivan Donchevskii <ivan.donchevskii@qt.io> | 2017-08-18 12:10:02 +0000 |
commit | 9c9baaac04f2d5f3fc0c3e429c1a4b7e9ba35824 (patch) | |
tree | b14a5a53096179892f0d276cf89298c5c30bc9f9 | |
parent | 32d38789f9bb322ef9510cf79c1ce0de017e07b6 (diff) |
Clang: add unit-tests for follow symbol
Change-Id: I336fe29052237ede6f5c578daf01557400d9027c
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
-rw-r--r-- | src/tools/clangbackend/ipcsource/clangfollowsymboljob.h | 6 | ||||
-rw-r--r-- | tests/unit/unittest/clangcodemodelserver-test.cpp | 44 | ||||
-rw-r--r-- | tests/unit/unittest/clangfollowsymbol-test.cpp | 366 | ||||
-rw-r--r-- | tests/unit/unittest/data/followsymbol_header.h | 59 | ||||
-rw-r--r-- | tests/unit/unittest/data/followsymbol_main.cpp | 67 | ||||
-rw-r--r-- | tests/unit/unittest/readandwritemessageblock-test.cpp | 9 | ||||
-rw-r--r-- | tests/unit/unittest/unittest.pro | 1 |
7 files changed, 552 insertions, 0 deletions
diff --git a/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h b/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h index cd96b7158d..2d56e2ca10 100644 --- a/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h +++ b/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h @@ -41,6 +41,12 @@ public: , failedToFollow(failedToFollow) {} + friend bool operator==(const FollowSymbolResult &first, const FollowSymbolResult &second) + { + return first.range == second.range + && first.failedToFollow == second.failedToFollow; + } + SourceRangeContainer range; bool failedToFollow = false; }; diff --git a/tests/unit/unittest/clangcodemodelserver-test.cpp b/tests/unit/unittest/clangcodemodelserver-test.cpp index 0dad554a0b..eeb500215b 100644 --- a/tests/unit/unittest/clangcodemodelserver-test.cpp +++ b/tests/unit/unittest/clangcodemodelserver-test.cpp @@ -126,6 +126,7 @@ protected: void requestDocumentAnnotations(const Utf8String &filePath); void requestReferences(quint32 documentRevision = 0); + void requestFollowSymbol(quint32 documentRevision = 0); void completeCode(const Utf8String &filePath, uint line = 1, uint column = 1, const Utf8String &projectPartId = Utf8String()); @@ -144,6 +145,7 @@ protected: void expectCompletionFromFileAUnsavedMethodVersion2(); void expectNoCompletionWithUnsavedMethod(); void expectReferences(); + void expectFollowSymbol(); void expectDocumentAnnotationsChangedForFileBWithSpecificHighlightingMark(); static const Utf8String unsavedContent(const QString &unsavedFilePath); @@ -206,6 +208,25 @@ TEST_F(ClangCodeModelServerSlowTest, RequestReferencesTakesRevisionFromMessage) queue.clear(); // Avoid blocking } +TEST_F(ClangCodeModelServerSlowTest, RequestFollowSymbolForCurrentDocumentRevision) +{ + registerProjectAndFileAndWaitForFinished(filePathC); + + expectFollowSymbol(); + requestFollowSymbol(); +} + +TEST_F(ClangCodeModelServerSlowTest, RequestFollowSymbolTakesRevisionFromMessage) +{ + registerProjectAndFileAndWaitForFinished(filePathC); + + requestFollowSymbol(/*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; @@ -555,6 +576,20 @@ void ClangCodeModelServer::expectReferences() .Times(1); } +void ClangCodeModelServer::expectFollowSymbol() +{ + const ClangBackEnd::SourceRangeContainer classDefinition{ + {filePathC, 40, 7}, + {filePathC, 40, 10} + }; + + EXPECT_CALL(mockClangCodeModelClient, + followSymbol( + Property(&FollowSymbolMessage::sourceRange, + Eq(classDefinition)))) + .Times(1); +} + void ClangCodeModelServer::expectCompletionFromFileA() { const CodeCompletion completion(Utf8StringLiteral("Function"), @@ -580,6 +615,15 @@ void ClangCodeModelServer::requestReferences(quint32 documentRevision) clangServer.requestReferences(message); } +void ClangCodeModelServer::requestFollowSymbol(quint32 documentRevision) +{ + const FileContainer fileContainer{filePathC, projectPartId, Utf8StringVector(), + documentRevision}; + const RequestFollowSymbolMessage message{fileContainer, QVector<Utf8String>(), 43, 9}; + + clangServer.requestFollowSymbol(message); +} + void ClangCodeModelServer::expectDocumentAnnotationsChangedForFileBWithSpecificHighlightingMark() { HighlightingTypes types; diff --git a/tests/unit/unittest/clangfollowsymbol-test.cpp b/tests/unit/unittest/clangfollowsymbol-test.cpp new file mode 100644 index 0000000000..7346e31c25 --- /dev/null +++ b/tests/unit/unittest/clangfollowsymbol-test.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** 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 "testenvironment.h" + +#include <clangbackendipc_global.h> +#include <clangfollowsymboljob.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 <commandlinearguments.h> + +#include <utils/qtcassert.h> + +#include <clang-c/Index.h> + +using ::testing::Contains; +using ::testing::Not; +using ::testing::ContainerEq; +using ::testing::Eq; +using ::testing::PrintToString; + +using ::ClangBackEnd::ProjectPart; +using ::ClangBackEnd::SourceLocationContainer; +using ::ClangBackEnd::Document; +using ::ClangBackEnd::UnsavedFiles; +using ::ClangBackEnd::ReferencesResult; +using ::ClangBackEnd::SourceRangeContainer; + +using ClangBackEnd::FollowSymbolResult; + +namespace { +const Utf8String sourceFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_main.cpp"); +const Utf8String headerFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_header.h"); +const Utf8String cursorPath = Utf8StringLiteral(TESTDATA_DIR"/cursor.cpp"); + +std::ostream &operator<<(std::ostream &os, const FollowSymbolResult &result) +{ + os << result.range; + + return os; +} + +MATCHER_P3(MatchesHeaderSourceRange, line, column, length, + std::string(negation ? "isn't " : "is ") + + PrintToString(SourceRangeContainer { + SourceLocationContainer(headerFilePath, line, column), + SourceLocationContainer(headerFilePath, line, column + length) + }) + ) +{ + const SourceRangeContainer expected = { + SourceLocationContainer(headerFilePath, line, column), + SourceLocationContainer(headerFilePath, line, column + length) + }; + + return arg == FollowSymbolResult {expected, false}; +} + +MATCHER_P3(MatchesSourceRange, line, column, length, + std::string(negation ? "isn't " : "is ") + + PrintToString(SourceRangeContainer { + SourceLocationContainer(sourceFilePath, line, column), + SourceLocationContainer(sourceFilePath, line, column + length) + }) + ) +{ + const SourceRangeContainer expected = { + SourceLocationContainer(sourceFilePath, line, column), + SourceLocationContainer(sourceFilePath, line, column + length) + }; + + return arg == FollowSymbolResult {expected, false}; +} + +MATCHER_P4(MatchesFileSourceRange, filename, line, column, length, + std::string(negation ? "isn't " : "is ") + + PrintToString(SourceRangeContainer { + SourceLocationContainer(filename, line, column), + SourceLocationContainer(filename, line, column + length) + }) + ) +{ + const SourceRangeContainer expected = { + SourceLocationContainer(filename, line, column), + SourceLocationContainer(filename, line, column + length) + }; + + return arg == FollowSymbolResult {expected, false}; +} + +class Data { +public: + Data() + { + m_document.parse(); + m_headerDocument.parse(); + } + + const Document &document() const { return m_document; } + const Document &headerDocument() const { return m_headerDocument; } + const QVector<Utf8String> &deps() const { return m_deps; } +private: + ProjectPart m_projectPart{ + Utf8StringLiteral("projectPartId"), + TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++14")})}; + ClangBackEnd::ProjectParts m_projects; + ClangBackEnd::UnsavedFiles m_unsavedFiles; + ClangBackEnd::Documents m_documents{m_projects, m_unsavedFiles}; + Document m_document = {sourceFilePath, + m_projectPart, + Utf8StringVector(), + m_documents}; + Document m_headerDocument = {headerFilePath, + m_projectPart, + Utf8StringVector(), + m_documents}; + QVector<Utf8String> m_deps {sourceFilePath, cursorPath}; +}; + +class FollowSymbol : public ::testing::Test +{ +protected: + FollowSymbolResult followSymbol(uint line, uint column) + { + ClangBackEnd::TranslationUnitUpdateInput updateInput = d->document().createUpdateInput(); + const ClangBackEnd::CommandLineArguments currentArgs(updateInput.filePath.constData(), + updateInput.projectArguments, + updateInput.fileArguments, + false); + return d->document().translationUnit().followSymbol(line, column, + d->deps(), + currentArgs); + } + + FollowSymbolResult followHeaderSymbol(uint line, uint column) + { + ClangBackEnd::TranslationUnitUpdateInput updateInput + = d->headerDocument().createUpdateInput(); + const ClangBackEnd::CommandLineArguments currentArgs(updateInput.filePath.constData(), + updateInput.projectArguments, + updateInput.fileArguments, + false); + return d->headerDocument().translationUnit().followSymbol(line, column, + d->deps(), + currentArgs); + } + + static void SetUpTestCase(); + static void TearDownTestCase(); + +private: + static std::unique_ptr<Data> d; +}; + +TEST_F(FollowSymbol, CursorOnNamespace) +{ + const auto namespaceDefinition = followSymbol(27, 1); + + ASSERT_THAT(namespaceDefinition, MatchesHeaderSourceRange(28, 11, 6)); +} + +TEST_F(FollowSymbol, CursorOnClassReference) +{ + const auto classDefinition = followSymbol(27, 9); + + ASSERT_THAT(classDefinition, MatchesHeaderSourceRange(34, 7, 3)); +} + +TEST_F(FollowSymbol, CursorOnClassForwardDeclarationFollowToHeader) +{ + const auto classDefinition = followHeaderSymbol(32, 7); + + ASSERT_THAT(classDefinition, MatchesHeaderSourceRange(34, 7, 3)); +} + +TEST_F(FollowSymbol, CursorOnClassForwardDeclarationFollowToCpp) +{ + const auto classDefinition = followHeaderSymbol(48, 9); + + ASSERT_THAT(classDefinition, MatchesSourceRange(54, 7, 8)); +} + +TEST_F(FollowSymbol, CursorOnClassDefinition) +{ + const auto classForwardDeclaration = followHeaderSymbol(34, 7); + + ASSERT_THAT(classForwardDeclaration, MatchesHeaderSourceRange(32, 7, 3)); +} + +TEST_F(FollowSymbol, CursorOnClassDefinitionInCpp) +{ + const auto classForwardDeclaration = followSymbol(54, 7); + + ASSERT_THAT(classForwardDeclaration, MatchesHeaderSourceRange(48, 7, 8)); +} + +TEST_F(FollowSymbol, CursorOnConstructorDeclaration) +{ + const auto constructorDefinition = followHeaderSymbol(36, 5); + + ASSERT_THAT(constructorDefinition, MatchesSourceRange(27, 14, 3)); +} + +TEST_F(FollowSymbol, CursorOnConstructorDefinition) +{ + const auto constructorDeclaration = followSymbol(27, 14); + + ASSERT_THAT(constructorDeclaration, MatchesHeaderSourceRange(36, 5, 3)); +} + +TEST_F(FollowSymbol, CursorOnMemberReference) +{ + const auto memberDeclaration = followSymbol(39, 10); + + ASSERT_THAT(memberDeclaration, MatchesHeaderSourceRange(38, 18, 6)); +} + +TEST_F(FollowSymbol, CursorOnMemberDeclaration) +{ + const auto sameMemberDeclaration = followHeaderSymbol(38, 18); + + ASSERT_THAT(sameMemberDeclaration, MatchesHeaderSourceRange(38, 18, 6)); +} + +TEST_F(FollowSymbol, CursorOnFunctionReference) +{ + const auto functionDefinition = followSymbol(66, 12); + + ASSERT_THAT(functionDefinition, MatchesSourceRange(35, 5, 3)); +} + +TEST_F(FollowSymbol, CursorOnMemberFunctionReference) +{ + const auto memberFunctionDefinition = followSymbol(42, 12); + + ASSERT_THAT(memberFunctionDefinition, MatchesSourceRange(49, 21, 3)); +} + +TEST_F(FollowSymbol, CursorOnFunctionWithoutDefinitionReference) +{ + const auto functionDeclaration = followSymbol(43, 5); + + ASSERT_THAT(functionDeclaration, MatchesHeaderSourceRange(59, 5, 3)); +} + +TEST_F(FollowSymbol, CursorOnFunctionDefinition) +{ + const auto functionDeclaration = followSymbol(35, 5); + + ASSERT_THAT(functionDeclaration, MatchesHeaderSourceRange(52, 5, 3)); +} + +TEST_F(FollowSymbol, CursorOnMemberFunctionDefinition) +{ + const auto memberFunctionDeclaration = followSymbol(49, 21); + + ASSERT_THAT(memberFunctionDeclaration, MatchesHeaderSourceRange(43, 9, 3)); +} + +TEST_F(FollowSymbol, CursorOnMemberFunctionDeclaration) +{ + const auto memberFunctionDefinition = followHeaderSymbol(43, 9); + + ASSERT_THAT(memberFunctionDefinition, MatchesSourceRange(49, 21, 3)); +} + +TEST_F(FollowSymbol, CursorOnInclude) +{ + const auto startOfIncludeFile = followSymbol(25, 13); + + ASSERT_THAT(startOfIncludeFile, MatchesHeaderSourceRange(1, 1, 0)); +} + +TEST_F(FollowSymbol, CursorOnLocalVariable) +{ + const auto variableDeclaration = followSymbol(39, 6); + + ASSERT_THAT(variableDeclaration, MatchesSourceRange(36, 9, 3)); +} + +TEST_F(FollowSymbol, CursorOnClassAlias) +{ + const auto aliasDefinition = followSymbol(36, 5); + + ASSERT_THAT(aliasDefinition, MatchesSourceRange(33, 7, 3)); +} + +TEST_F(FollowSymbol, CursorOnStaticVariable) +{ + const auto staticVariableDeclaration = followSymbol(40, 27); + + ASSERT_THAT(staticVariableDeclaration, MatchesHeaderSourceRange(30, 7, 7)); +} + +TEST_F(FollowSymbol, CursorOnFunctionFromOtherClass) +{ + const auto functionDefinition = followSymbol(62, 39); + + ASSERT_THAT(functionDefinition, MatchesFileSourceRange(cursorPath, 104, 22, 8)); +} + +TEST_F(FollowSymbol, CursorOnDefineReference) +{ + const auto functionDefinition = followSymbol(66, 43); + + ASSERT_THAT(functionDefinition, MatchesHeaderSourceRange(27, 9, 11)); +} + + +TEST_F(FollowSymbol, CursorInTheMiddleOfNamespace) +{ + const auto namespaceDefinition = followSymbol(27, 3); + + ASSERT_THAT(namespaceDefinition, MatchesHeaderSourceRange(28, 11, 6)); +} + +TEST_F(FollowSymbol, CursorAfterNamespace) +{ + const auto namespaceDefinition = followSymbol(27, 7); + + ASSERT_THAT(namespaceDefinition, MatchesFileSourceRange(QString(""), 0, 0, 0)); +} + +std::unique_ptr<Data> FollowSymbol::d; + +void FollowSymbol::SetUpTestCase() +{ + d.reset(new Data); +} + +void FollowSymbol::TearDownTestCase() +{ + d.reset(); +} + +} // anonymous namespace diff --git a/tests/unit/unittest/data/followsymbol_header.h b/tests/unit/unittest/data/followsymbol_header.h new file mode 100644 index 0000000000..8630834023 --- /dev/null +++ b/tests/unit/unittest/data/followsymbol_header.h @@ -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); diff --git a/tests/unit/unittest/data/followsymbol_main.cpp b/tests/unit/unittest/data/followsymbol_main.cpp new file mode 100644 index 0000000000..3727f494cf --- /dev/null +++ b/tests/unit/unittest/data/followsymbol_main.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 "followsymbol_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; +} diff --git a/tests/unit/unittest/readandwritemessageblock-test.cpp b/tests/unit/unittest/readandwritemessageblock-test.cpp index a95e2866b4..ac57f83398 100644 --- a/tests/unit/unittest/readandwritemessageblock-test.cpp +++ b/tests/unit/unittest/readandwritemessageblock-test.cpp @@ -203,6 +203,15 @@ TEST_F(ReadAndWriteMessageBlock, CompareRequestReferences) CompareMessage(ClangBackEnd::RequestReferencesMessage{fileContainer, 13, 37}); } +TEST_F(ReadAndWriteMessageBlock, CompareRequestFollowSymbol) +{ + QVector<Utf8String> dependentFiles; + dependentFiles.push_back(QString("somefile.cpp")); + dependentFiles.push_back(QString("otherfile.cpp")); + CompareMessage(ClangBackEnd::RequestFollowSymbolMessage{fileContainer, dependentFiles, 13, 37, + false}); +} + TEST_F(ReadAndWriteMessageBlock, CompareReferences) { const QVector<ClangBackEnd::SourceRangeContainer> references{ diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 67226416af..8a29b173aa 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -37,6 +37,7 @@ DEFINES += CPPTOOLS_JSON=\"R\\\"xxx($${cpptoolsjson.output})xxx\\\"\" SOURCES += \ changedfilepathcompressor-test.cpp \ + clangfollowsymbol-test.cpp \ clangpathwatcher-test.cpp \ clangqueryexamplehighlightmarker-test.cpp \ clangqueryhighlightmarker-test.cpp \ |