/**************************************************************************** ** ** 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