From 76c25bcd6a97dda3921e8bc487e1c61f10938ad2 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 12 Jan 2018 12:29:43 +0100 Subject: Clang: Provide tooltips This includes also the query data for the help system (F1) for an identifier under cursor. Regressions (libclang changes necessary): - Function signatures do not contain default values. - Aliases are not resolved for/at: - template types - qualified name of a type Fixes/Improvements: - Resolve "auto" - On a template type, show also the template parameter. - For a typedef like typedef long long superlong; the tooltip was "long long superlong", which was confusing. Now, "long long" is shown. New: - Show first or \brief paragraph of a documentation comment. - Show size of a class at definition. - Show size of a field member in class definition. Task-number: QTCREATORBUG-11259 Change-Id: Ie1a07930d0e882015d07dc43e35bb81a685cdeb8 Reviewed-by: Marco Bubke --- tests/unit/echoserver/echoclangcodemodelserver.cpp | 5 + tests/unit/echoserver/echoclangcodemodelserver.h | 1 + tests/unit/unittest/clangtooltipinfo-test.cpp | 628 +++++++++++++++++++++ tests/unit/unittest/conditionally-disabled-tests.h | 6 + tests/unit/unittest/data/tooltipinfo.cpp | 180 ++++++ tests/unit/unittest/data/tooltipinfo.h | 3 + tests/unit/unittest/dummyclangipcclient.h | 1 + tests/unit/unittest/gtest-creator-printing.cpp | 46 +- tests/unit/unittest/gtest-creator-printing.h | 6 + tests/unit/unittest/mockclangcodemodelclient.h | 2 + tests/unit/unittest/mockclangcodemodelserver.h | 2 + tests/unit/unittest/unittest.pro | 1 + tests/unit/unittest/unsavedfile-test.cpp | 28 + 13 files changed, 908 insertions(+), 1 deletion(-) create mode 100644 tests/unit/unittest/clangtooltipinfo-test.cpp create mode 100644 tests/unit/unittest/data/tooltipinfo.cpp create mode 100644 tests/unit/unittest/data/tooltipinfo.h (limited to 'tests') diff --git a/tests/unit/echoserver/echoclangcodemodelserver.cpp b/tests/unit/echoserver/echoclangcodemodelserver.cpp index 2c0fea98c93..38d2d395444 100644 --- a/tests/unit/echoserver/echoclangcodemodelserver.cpp +++ b/tests/unit/echoserver/echoclangcodemodelserver.cpp @@ -98,6 +98,11 @@ void EchoClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMess echoMessage(message); } +void EchoClangCodeModelServer::requestToolTip(const RequestToolTipMessage &message) +{ + echoMessage(message); +} + void EchoClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) { echoMessage(message); diff --git a/tests/unit/echoserver/echoclangcodemodelserver.h b/tests/unit/echoserver/echoclangcodemodelserver.h index 2dc8c30913a..d3452d2d321 100644 --- a/tests/unit/echoserver/echoclangcodemodelserver.h +++ b/tests/unit/echoserver/echoclangcodemodelserver.h @@ -47,6 +47,7 @@ public: void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override; void requestReferences(const RequestReferencesMessage &message) override; void requestFollowSymbol(const RequestFollowSymbolMessage &message) override; + void requestToolTip(const RequestToolTipMessage &message) override; void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override; private: diff --git a/tests/unit/unittest/clangtooltipinfo-test.cpp b/tests/unit/unittest/clangtooltipinfo-test.cpp new file mode 100644 index 00000000000..4f6c9806496 --- /dev/null +++ b/tests/unit/unittest/clangtooltipinfo-test.cpp @@ -0,0 +1,628 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "rundocumentparse-utility.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using ::ClangBackEnd::ProjectPart; +using ::ClangBackEnd::SourceLocationContainer; +using ::ClangBackEnd::Document; +using ::ClangBackEnd::UnsavedFiles; +using ::ClangBackEnd::ToolTipInfo; +using ::ClangBackEnd::SourceRangeContainer; + +namespace { + +#define CHECK_MEMBER(actual, expected, memberName) \ + if (actual.memberName() != expected.memberName()) { \ + *result_listener << #memberName " is " + PrintToString(actual.memberName()) \ + << " and not " + PrintToString(expected.memberName()); \ + return false; \ + } + +MATCHER_P(IsToolTip, expected, std::string(negation ? "isn't" : "is") + PrintToString(expected)) +{ + CHECK_MEMBER(arg, expected, text); + CHECK_MEMBER(arg, expected, briefComment); + + CHECK_MEMBER(arg, expected, qdocIdCandidates); + CHECK_MEMBER(arg, expected, qdocMark); + CHECK_MEMBER(arg, expected, qdocCategory); + + CHECK_MEMBER(arg, expected, sizeInBytes); + + return true; +} + +MATCHER_P(IsQdocToolTip, expected, std::string(negation ? "isn't" : "is") + PrintToString(expected)) +{ + CHECK_MEMBER(arg, expected, qdocIdCandidates); + CHECK_MEMBER(arg, expected, qdocMark); + CHECK_MEMBER(arg, expected, qdocCategory); + + return true; +} + +#undef CHECK_MEMBER + +struct Data { + ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++14")}}; + ClangBackEnd::ProjectParts projects; + ClangBackEnd::UnsavedFiles unsavedFiles; + ClangBackEnd::Documents documents{projects, unsavedFiles}; + Document document{Utf8StringLiteral(TESTDATA_DIR "/tooltipinfo.cpp"), + projectPart, + {}, + documents}; + UnitTest::RunDocumentParse _1{document}; +}; + +class ToolTipInfo : public ::testing::Test +{ +protected: + ::ToolTipInfo tooltip(uint line, uint column) + { + return d->document.translationUnit().tooltip(d->unsavedFiles, + Utf8StringLiteral("UTF-8"), + line, + column); + } + + static void SetUpTestCase(); + static void TearDownTestCase(); + +private: + static std::unique_ptr d; +}; + +TEST_F(ToolTipInfo, LocalVariableInt) +{ + const ::ToolTipInfo actual = tooltip(3, 5); + + ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("int")))); +} + +TEST_F(ToolTipInfo, LocalVariablePointerToConstInt) +{ + const ::ToolTipInfo actual = tooltip(4, 5); + + ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("const int *")))); +} + +TEST_F(ToolTipInfo, LocalParameterVariableConstRefCustomType) +{ + ::ToolTipInfo expected(Utf8StringLiteral("const Foo &")); + expected.setQdocIdCandidates({Utf8StringLiteral("Foo")}); + expected.setQdocMark(Utf8StringLiteral("Foo")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(12, 12); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, LocalNonParameterVariableConstRefCustomType) +{ + ::ToolTipInfo expected(Utf8StringLiteral("const Foo")); + expected.setQdocIdCandidates({Utf8StringLiteral("Foo")}); + expected.setQdocMark(Utf8StringLiteral("Foo")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(14, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, MemberVariable) +{ + const ::ToolTipInfo actual = tooltip(12, 16); + + ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("int")))); +} + +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(MemberFunctionCall_QualifiedName)) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("int Bar::mem()")); +} + +// ChangeLog: Show extra specifiers. For functions e.g.: virtual, inline, explicit, const, volatile +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(MemberFunctionCall_ExtraSpecifiers)) +{ + const ::ToolTipInfo actual = tooltip(22, 9); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("virtual int Bar::virtualConstMem() const")); +} + +TEST_F(ToolTipInfo, MemberFunctionCall_qdocIdCandidates) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("Bar::mem"), + Utf8StringLiteral("mem"))); +} + +TEST_F(ToolTipInfo, MemberFunctionCall_qdocMark_FIXLIBCLANG_CHECKED) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("mem()")); +} + +// TODO: Check what is really needed for qdoc before implementing this one. +TEST_F(ToolTipInfo, DISABLED_MemberFunctionCall_qdocMark_extraSpecifiers) +{ + const ::ToolTipInfo actual = tooltip(22, 9); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("virtualConstMem() const")); +} + +TEST_F(ToolTipInfo, MemberFunctionCall_qdocCategory) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.qdocCategory(), ::ToolTipInfo::Function); +} + +// TODO: Show the template parameter type, too: "template...)" +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(TemplateFunctionCall)) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("template<> void t(int foo)")); +} + +TEST_F(ToolTipInfo, TemplateFunctionCall_qdocIdCandidates) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("t"))); +} + +TEST_F(ToolTipInfo, TemplateFunctionCall_qdocMark_FIXLIBCLANG_CHECKED) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("t(int)")); +} + +TEST_F(ToolTipInfo, TemplateFunctionCall_qdocCategory) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.qdocCategory(), ::ToolTipInfo::Function); +} + +TEST_F(ToolTipInfo, BriefComment) +{ + const ::ToolTipInfo actual = tooltip(41, 5); + + ASSERT_THAT(actual.briefComment(), Utf8StringLiteral("This is a crazy function.")); +} + +TEST_F(ToolTipInfo, Enum) +{ + ::ToolTipInfo expected(Utf8StringLiteral("EnumType")); + expected.setQdocIdCandidates({Utf8StringLiteral("EnumType")}); + expected.setQdocMark(Utf8StringLiteral("EnumType")); + expected.setQdocCategory(::ToolTipInfo::Enum); + + const ::ToolTipInfo actual = tooltip(49, 12); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, Enumerator) +{ + ::ToolTipInfo expected(Utf8StringLiteral("6")); + expected.setQdocIdCandidates({Utf8StringLiteral("Custom")}); + expected.setQdocMark(Utf8StringLiteral("EnumType")); + expected.setQdocCategory(::ToolTipInfo::Enum); + + const ::ToolTipInfo actual = tooltip(49, 22); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateTypeFromParameter) +{ + ::ToolTipInfo expected(Utf8StringLiteral("const Baz &")); + expected.setQdocIdCandidates({Utf8StringLiteral("Baz")}); + expected.setQdocMark(Utf8StringLiteral("Baz")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(55, 25); + + ASSERT_THAT(actual, IsQdocToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateTypeFromNonParameter) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Baz")); + expected.setQdocIdCandidates({Utf8StringLiteral("Baz")}); + expected.setQdocMark(Utf8StringLiteral("Baz")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(56, 19); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, IncludeDirective) +{ + ::ToolTipInfo expected(Utf8StringLiteral(TESTDATA_DIR"/tooltipinfo.h")); + expected.setQdocIdCandidates({Utf8StringLiteral("tooltipinfo.h")}); + expected.setQdocMark(Utf8StringLiteral("tooltipinfo.h")); + expected.setQdocCategory(::ToolTipInfo::Brief); + + const ::ToolTipInfo actual = tooltip(59, 11); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, MacroUse_WithMacroFromSameFile) +{ + const ::ToolTipInfo actual = tooltip(66, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("#define MACRO_FROM_MAINFILE(x) x + 3")); +} + +TEST_F(ToolTipInfo, MacroUse_WithMacroFromHeader) +{ + const ::ToolTipInfo actual = tooltip(67, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("#define MACRO_FROM_HEADER(x) x + \\\n x + \\\n x")); +} + +TEST_F(ToolTipInfo, MacroUse_qdoc) +{ + ::ToolTipInfo expected; + expected.setQdocIdCandidates({Utf8StringLiteral("MACRO_FROM_MAINFILE")}); + expected.setQdocMark(Utf8StringLiteral("MACRO_FROM_MAINFILE")); + expected.setQdocCategory(::ToolTipInfo::Macro); + + const ::ToolTipInfo actual = tooltip(66, 5); + + ASSERT_THAT(actual, IsQdocToolTip(expected)); +} + +TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDirectiveIsQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Muu")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")}); + expected.setQdocMark(Utf8StringLiteral("Muu")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(77, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDirectiveOfAliasIsResolvedAndQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Muu")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")}); + expected.setQdocMark(Utf8StringLiteral("Muu")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(82, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDeclarationIsQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Muu")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")}); + expected.setQdocMark(Utf8StringLiteral("Muu")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(87, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, SizeForClassDefinition) +{ + const ::ToolTipInfo actual = tooltip(92, 8); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("2")); +} + +TEST_F(ToolTipInfo, SizeForMemberField) +{ + const ::ToolTipInfo actual = tooltip(95, 10); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("1")); +} + +TEST_F(ToolTipInfo, SizeForEnum) +{ + const ::ToolTipInfo actual = tooltip(97, 12); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("4")); +} + +TEST_F(ToolTipInfo, SizeForUnion) +{ + const ::ToolTipInfo actual = tooltip(98, 7); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("1")); +} + +TEST_F(ToolTipInfo, Namespace) +{ + ::ToolTipInfo expected(Utf8StringLiteral("X")); + expected.setQdocIdCandidates({Utf8StringLiteral("X")}); + expected.setQdocMark(Utf8StringLiteral("X")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(106, 11); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, NamespaceQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("X::Y")); + expected.setQdocIdCandidates({Utf8StringLiteral("X::Y"), Utf8StringLiteral("Y")}); + expected.setQdocMark(Utf8StringLiteral("Y")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(107, 11); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// TODO: Show unresolved and resolved name, for F1 try both. +TEST_F(ToolTipInfo, TypeName_ResolveTypeDef) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Ptr")); + expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTypeDef")}); + expected.setQdocMark(Utf8StringLiteral("PtrFromTypeDef")); + expected.setQdocCategory(::ToolTipInfo::Typedef); + + const ::ToolTipInfo actual = tooltip(122, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// TODO: Show unresolved and resolved name, for F1 try both. +TEST_F(ToolTipInfo, TypeName_ResolveAlias) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Ptr")); + expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTypeAlias")}); + expected.setQdocMark(Utf8StringLiteral("PtrFromTypeAlias")); + expected.setQdocCategory(::ToolTipInfo::Typedef); + + const ::ToolTipInfo actual = tooltip(123, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// The referenced cursor is a CXCursor_TypeAliasTemplateDecl, its type is invalid +// and so probably clang_getTypedefDeclUnderlyingType() does not return anything useful. +// TODO: Fix the cursor's type or add new API in libclang for querying the template type alias. +TEST_F(ToolTipInfo, DISABLED_TypeName_ResolveTemplateTypeAlias) +{ + const ::ToolTipInfo actual = tooltip(124, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("Ptr")); +} + +TEST_F(ToolTipInfo, TypeName_ResolveTemplateTypeAlias_qdoc) +{ + ::ToolTipInfo expected; + expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTemplateTypeAlias")}); + expected.setQdocMark(Utf8StringLiteral("PtrFromTemplateTypeAlias")); + expected.setQdocCategory(::ToolTipInfo::Typedef); + + const ::ToolTipInfo actual = tooltip(124, 5); + + ASSERT_THAT(actual, IsQdocToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateClassReference) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Zii")); + expected.setQdocIdCandidates({Utf8StringLiteral("Zii")}); + expected.setQdocMark(Utf8StringLiteral("Zii")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(134, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateClassQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("U::Yii")); + expected.setQdocIdCandidates({Utf8StringLiteral("U::Yii"), Utf8StringLiteral("Yii")}); + expected.setQdocMark(Utf8StringLiteral("Yii")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(135, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, ResolveNamespaceAliasForType) +{ + ::ToolTipInfo expected(Utf8StringLiteral("A::X")); + expected.setQdocIdCandidates({Utf8StringLiteral("A::X"), Utf8StringLiteral("X")}); + expected.setQdocMark(Utf8StringLiteral("X")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(144, 8); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// TODO: Show unresolved and resolved name, for F1 try both. +TEST_F(ToolTipInfo, ResolveNamespaceAlias) +{ + ::ToolTipInfo expected(Utf8StringLiteral("A")); + expected.setQdocIdCandidates({Utf8StringLiteral("B")}); + expected.setQdocMark(Utf8StringLiteral("B")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(144, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, QualificationForTemplateClassInClassInNamespace) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Outer::Inner")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Outer::Inner"), + Utf8StringLiteral("Outer::Inner"), + Utf8StringLiteral("Inner")}); + expected.setQdocMark(Utf8StringLiteral("Inner")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + expected.setSizeInBytes(Utf8StringLiteral("1")); + + const ::ToolTipInfo actual = tooltip(153, 16); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, Function) +{ + ::ToolTipInfo expected(Utf8StringLiteral("void f()")); + expected.setQdocIdCandidates({Utf8StringLiteral("f")}); + expected.setQdocMark(Utf8StringLiteral("f()")); + expected.setQdocCategory(::ToolTipInfo::Function); + + const ::ToolTipInfo actual = tooltip(165, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, Function_QualifiedName) +{ + const ::ToolTipInfo actual = tooltip(166, 8); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("void R::f()")); +} + +TEST_F(ToolTipInfo, Function_qdocIdCandidatesAreQualified) +{ + const ::ToolTipInfo actual = tooltip(166, 8); + + ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("R::f"), + Utf8StringLiteral("f"))); +} + +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(Function_HasParameterName)) +{ + const ::ToolTipInfo actual = tooltip(167, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("void f(int param)")); +} + +// TODO: Implement with CXPrintingPolicy +TEST_F(ToolTipInfo, DISABLED_Function_HasDefaultArgument) +{ + const ::ToolTipInfo actual = tooltip(168, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("void z(int = 1)")); +} + +TEST_F(ToolTipInfo, Function_qdocMarkHasNoParameterName) +{ + const ::ToolTipInfo actual = tooltip(167, 5); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("f(int)")); +} + +TEST_F(ToolTipInfo, Function_qdocMarkHasNoDefaultArgument) +{ + const ::ToolTipInfo actual = tooltip(168, 5); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("z(int)")); +} + +TEST_F(ToolTipInfo, AutoTypeBuiltin) +{ + const ::ToolTipInfo actual = tooltip(176, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("int")); +} + +// TODO: Test for qdoc entries, too. +TEST_F(ToolTipInfo, AutoTypeEnum) +{ + const ::ToolTipInfo actual = tooltip(177, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("EnumType")); +} + +// TODO: Test for qdoc entries, too. +TEST_F(ToolTipInfo, AutoTypeClassType) +{ + const ::ToolTipInfo actual = tooltip(178, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("Bar")); +} + +// TODO: Test for qdoc entries, too. +// TODO: Deduced template arguments work, too?! +TEST_F(ToolTipInfo, AutoTypeClassTemplateType) +{ + const ::ToolTipInfo actual = tooltip(179, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("Zii")); +} + +std::unique_ptr ToolTipInfo::d; + +void ToolTipInfo::SetUpTestCase() +{ + d.reset(new Data); +} + +void ToolTipInfo::TearDownTestCase() +{ + d.reset(); +} + +} // anonymous namespace diff --git a/tests/unit/unittest/conditionally-disabled-tests.h b/tests/unit/unittest/conditionally-disabled-tests.h index 27e6fe173b2..8f55db10d7a 100644 --- a/tests/unit/unittest/conditionally-disabled-tests.h +++ b/tests/unit/unittest/conditionally-disabled-tests.h @@ -33,3 +33,9 @@ #else # define DISABLED_ON_WINDOWS(x) x #endif + +#ifdef IS_PRETTY_DECL_SUPPORTED +# define DISABLED_WITHOUT_PRETTYDECL_PATCH(x) x +#else +# define DISABLED_WITHOUT_PRETTYDECL_PATCH(x) DISABLED_##x +#endif diff --git a/tests/unit/unittest/data/tooltipinfo.cpp b/tests/unit/unittest/data/tooltipinfo.cpp new file mode 100644 index 00000000000..1945577b635 --- /dev/null +++ b/tests/unit/unittest/data/tooltipinfo.cpp @@ -0,0 +1,180 @@ +void f(int foo, const int *cfoo) +{ + foo++; + cfoo++; +} + + + +struct Foo { int member = 0; }; +int g(const Foo &foo) +{ + return foo.member; + const Foo bar; + bar; +} + +struct Bar { virtual ~Bar(); int mem(){} virtual int virtualConstMem() const; }; +void h(const Foo &foo, Bar &bar) +{ + g(foo); + bar.mem(); + bar.virtualConstMem(); +} + + +template +void t(int foo) { (void)foo; } +void c() +{ + t(3); +} + + + +/** + * \brief This is a crazy function. + */ +void documentedFunction(); +void d() +{ + documentedFunction(); +} + + + +enum EnumType { V1, V2, Custom = V2 + 5 }; +EnumType e() +{ + return EnumType::Custom; +} + + + +template struct Baz { T member; }; +void t2(const Baz &b) { + Baz baz; baz = b; +} + +#include "tooltipinfo.h" + + + +#define MACRO_FROM_MAINFILE(x) x + 3 +void foo() +{ + MACRO_FROM_MAINFILE(7); + MACRO_FROM_HEADER(7); +} + + + +namespace N { struct Muu{}; } +namespace G = N; +void o() +{ + using namespace N; + Muu muu; (void)muu; +} +void n() +{ + using namespace G; + Muu muu; (void)muu; +} +void q() +{ + using N::Muu; + Muu muu; (void)muu; +} + + + +struct Sizes +{ + char memberChar1; + char memberChar2; +}; +enum class FancyEnumType { V1, V2 }; +union Union +{ + char memberChar1; + char memberChar2; +}; + + + +namespace X { +namespace Y { +} +} + + + +template struct Ptr {}; +struct Nuu {}; + +typedef Ptr PtrFromTypeDef; +using PtrFromTypeAlias = Ptr; +template using PtrFromTemplateTypeAlias = Ptr; + +void y() +{ + PtrFromTypeDef b; (void)b; + PtrFromTypeAlias a; (void)a; + PtrFromTemplateTypeAlias c; (void)c; +} + + + +template struct Zii {}; +namespace U { template struct Yii {}; } +void mc() +{ + using namespace U; + Zii zii; (void) zii; + Yii yii; (void) yii; +} + + + +namespace A { struct X {}; } +namespace B = A; +void ab() +{ + B::X x; (void)x; +} + + + +namespace N { +struct Outer +{ + template struct Inner {}; + Inner inner; +}; +} + + + +void f(); +namespace R { void f(); } +void f(int param); +void z(int = 1); +void user() +{ + f(); + R::f(); + f(1); + z(); +} + + + + +void autoTypes() +{ + auto a = 3; (void)a; + auto b = EnumType::V1; (void)b; + auto c = Bar(); (void)c; + auto d = Zii(); (void)d; +} diff --git a/tests/unit/unittest/data/tooltipinfo.h b/tests/unit/unittest/data/tooltipinfo.h new file mode 100644 index 00000000000..47d3bb92e75 --- /dev/null +++ b/tests/unit/unittest/data/tooltipinfo.h @@ -0,0 +1,3 @@ +#define MACRO_FROM_HEADER(x) x + \ + x + \ + x diff --git a/tests/unit/unittest/dummyclangipcclient.h b/tests/unit/unittest/dummyclangipcclient.h index 3908f9e89f2..e840b0a6c7a 100644 --- a/tests/unit/unittest/dummyclangipcclient.h +++ b/tests/unit/unittest/dummyclangipcclient.h @@ -38,4 +38,5 @@ public: void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &) override {} void references(const ClangBackEnd::ReferencesMessage &) override {} void followSymbol(const ClangBackEnd::FollowSymbolMessage &) override {} + void tooltip(const ClangBackEnd::ToolTipMessage &) override {} }; diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 2c106ec0e53..1bcf5f2b07d 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -269,6 +270,17 @@ std::ostream &operator<<(std::ostream &os, const ReferencesMessage &message) return os; } +std::ostream &operator<<(std::ostream &os, const ToolTipMessage &message) +{ + os << "(" + << message.fileContainer() << ", " + << message.ticketNumber() << ", " + << message.toolTipInfo() << ", " + << ")"; + + return os; +} + std::ostream &operator<<(std::ostream &os, const EchoMessage &/*message*/) { return os << "()"; @@ -385,7 +397,8 @@ std::ostream &operator<<(std::ostream &os, const FileContainer &container) << container.filePath() << ", " << container.projectPartId() << ", " << container.fileArguments() << ", " - << container.documentRevision(); + << container.documentRevision() << ", " + << container.textCodecName(); if (container.hasUnsavedFileContent()) os << ", " @@ -552,6 +565,37 @@ std::ostream &operator<<(std::ostream &os, const RequestReferencesMessage &messa return os; } +std::ostream &operator<<(std::ostream &out, const RequestToolTipMessage &message) +{ + out << "(" + << message.fileContainer() << ", " + << message.ticketNumber() << ", " + << message.line() << ", " + << message.column() << ", " + << ")"; + + return out; +} + +std::ostream &operator<<(std::ostream &os, const ToolTipInfo::QdocCategory category) +{ + return os << qdocCategoryToString(category); +} + +std::ostream &operator<<(std::ostream &out, const ToolTipInfo &info) +{ + out << "(" + << info.m_text << ", " + << info.m_briefComment << ", " + << info.m_qdocIdCandidates << ", " + << info.m_qdocMark << ", " + << info.m_qdocCategory + << info.m_sizeInBytes << ", " + << ")"; + + return out; +} + std::ostream &operator<<(std::ostream &os, const RequestSourceLocationsForRenamingMessage &message) { diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index e08b4b33c0b..d58daaf40c2 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -73,6 +73,7 @@ class CodeCompletedMessage; class EchoMessage; class DocumentAnnotationsChangedMessage; class ReferencesMessage; +class ToolTipMessage; class FollowSymbolMessage; class CompleteCodeMessage; class EndMessage; @@ -97,6 +98,7 @@ class RemovePchProjectPartsMessage; class RequestDocumentAnnotationsMessage; class RequestFollowSymbolMessage; class RequestReferencesMessage; +class RequestToolTipMessage; class RequestSourceLocationsForRenamingMessage; class RequestSourceRangesAndDiagnosticsForQueryMessage; class RequestSourceRangesForQueryMessage; @@ -114,6 +116,7 @@ class UpdateVisibleTranslationUnitsMessage; class FilePath; class TokenInfo; class TokenInfos; +class ToolTipInfo; std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry); std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths); @@ -127,6 +130,7 @@ std::ostream &operator<<(std::ostream &out, const CodeCompletedMessage &message) std::ostream &operator<<(std::ostream &out, const EchoMessage &message); std::ostream &operator<<(std::ostream &out, const DocumentAnnotationsChangedMessage &message); std::ostream &operator<<(std::ostream &out, const ReferencesMessage &message); +std::ostream &operator<<(std::ostream &out, const ToolTipMessage &message); std::ostream &operator<<(std::ostream &out, const FollowSymbolMessage &message); std::ostream &operator<<(std::ostream &out, const CompleteCodeMessage &message); std::ostream &operator<<(std::ostream &out, const EndMessage &message); @@ -153,6 +157,8 @@ std::ostream &operator<<(std::ostream &out, const RemovePchProjectPartsMessage & std::ostream &operator<<(std::ostream &out, const RequestDocumentAnnotationsMessage &message); std::ostream &operator<<(std::ostream &out, const RequestFollowSymbolMessage &message); std::ostream &operator<<(std::ostream &out, const RequestReferencesMessage &message); +std::ostream &operator<<(std::ostream &out, const RequestToolTipMessage &message); +std::ostream &operator<<(std::ostream &out, const ToolTipInfo &info); std::ostream &operator<<(std::ostream &out, const RequestSourceLocationsForRenamingMessage &message); std::ostream &operator<<(std::ostream &out, const RequestSourceRangesAndDiagnosticsForQueryMessage &message); std::ostream &operator<<(std::ostream &out, const RequestSourceRangesForQueryMessage &message); diff --git a/tests/unit/unittest/mockclangcodemodelclient.h b/tests/unit/unittest/mockclangcodemodelclient.h index 2e287909ddf..3b5a3cfbf5a 100644 --- a/tests/unit/unittest/mockclangcodemodelclient.h +++ b/tests/unit/unittest/mockclangcodemodelclient.h @@ -45,4 +45,6 @@ public: void(const ClangBackEnd::ReferencesMessage &message)); MOCK_METHOD1(followSymbol, void(const ClangBackEnd::FollowSymbolMessage &message)); + MOCK_METHOD1(tooltip, + void(const ClangBackEnd::ToolTipMessage &message)); }; diff --git a/tests/unit/unittest/mockclangcodemodelserver.h b/tests/unit/unittest/mockclangcodemodelserver.h index 8b6c66b2a33..468f683bf53 100644 --- a/tests/unit/unittest/mockclangcodemodelserver.h +++ b/tests/unit/unittest/mockclangcodemodelserver.h @@ -55,6 +55,8 @@ public: void(const ClangBackEnd::RequestReferencesMessage &message)); MOCK_METHOD1(requestFollowSymbol, void(const ClangBackEnd::RequestFollowSymbolMessage &message)); + MOCK_METHOD1(requestToolTip, + void(const ClangBackEnd::RequestToolTipMessage &message)); MOCK_METHOD1(updateVisibleTranslationUnits, void(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message)); }; diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index a16a13e88bf..b6a698361ae 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -118,6 +118,7 @@ SOURCES += \ clangstring-test.cpp \ clangsupportivetranslationunitinitializer-test.cpp \ clangsuspenddocumentjob-test.cpp \ + clangtooltipinfo-test.cpp \ clangtranslationunits-test.cpp \ clangtranslationunit-test.cpp \ clangupdatedocumentannotationsjob-test.cpp \ diff --git a/tests/unit/unittest/unsavedfile-test.cpp b/tests/unit/unittest/unsavedfile-test.cpp index 05783a33c32..7e4d3dae685 100644 --- a/tests/unit/unittest/unsavedfile-test.cpp +++ b/tests/unit/unittest/unsavedfile-test.cpp @@ -203,4 +203,32 @@ TEST_F(UnsavedFile, HasCharacterForLastLineColumn) ASSERT_TRUE(unsavedFile.hasCharacterAt(1, 7, 't')); } +TEST_F(UnsavedFile, LineRangeForInvalidLines) +{ + ::UnsavedFile unsavedFile(filePath, fileContent); + + ASSERT_THAT(unsavedFile.lineRange(2, 1), Utf8String()); +} + +TEST_F(UnsavedFile, LineRangeForSingleLine) +{ + ::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo")); + + ASSERT_THAT(unsavedFile.lineRange(1, 1), Utf8StringLiteral("foo")); +} + +TEST_F(UnsavedFile, LineRangeForSingleLineInMultipleLines) +{ + ::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo\nbar\n\baz")); + + ASSERT_THAT(unsavedFile.lineRange(2, 2), Utf8StringLiteral("bar")); +} + +TEST_F(UnsavedFile, LineRangeForTwoLines) +{ + ::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo\nbar\n\baz")); + + ASSERT_THAT(unsavedFile.lineRange(2, 3), Utf8StringLiteral("bar\n\baz")); +} + } // anonymous namespace -- cgit v1.2.3