/**************************************************************************** ** ** 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 "googletest.h" #include "unittest-utility-functions.h" #include #include #include #include #include #include #include #include #include #include #include #include using ClangBackEnd::CodeCompletionsExtractor; using ClangBackEnd::ClangCodeCompleteResults; using ClangBackEnd::FilePath; using ClangBackEnd::Document; using ClangBackEnd::CodeCompletion; using ClangBackEnd::UnsavedFiles; using ClangBackEnd::UnsavedFilesShallowArguments; using ClangBackEnd::CodeCompletionChunk; using ClangBackEnd::CodeCompletionChunks; namespace { using ::testing::PrintToString; using ::testing::Not; MATCHER_P3(HasCompletion, name, kind, availability, std::string(negation ? "hasn't" : "has") + " completion of name " + PrintToString(name) + ", kind " + PrintToString(kind)) { ::CodeCompletionsExtractor &extractor = const_cast<::CodeCompletionsExtractor&>(arg); while (extractor.next()) { if (extractor.currentCodeCompletion().text == name) { if (extractor.currentCodeCompletion().completionKind == kind) { if (extractor.currentCodeCompletion().availability == availability) { return true; } else if (!extractor.peek(name)) { *result_listener << "availability is " << PrintToString(extractor.currentCodeCompletion().availability) << " and not " << PrintToString(availability); return false; } } else if (!extractor.peek(name)) { *result_listener << "kind is " << PrintToString(extractor.currentCodeCompletion().completionKind) << " and not " << PrintToString(kind); return false; } } } return false; } MATCHER_P2(HasCompletionChunks, name, chunks, std::string(negation ? "hasn't" : "has") + " completion of name " + PrintToString(name) + " with the chunks " + PrintToString(chunks)) { ::CodeCompletionsExtractor &extractor = const_cast<::CodeCompletionsExtractor&>(arg); while (extractor.next()) { if (extractor.currentCodeCompletion().text == name) { if (extractor.currentCodeCompletion().chunks == chunks) { return true; } else if (!extractor.peek(name)) { *result_listener << "chunks are " << PrintToString(arg.currentCodeCompletion().chunks) << " and not " << PrintToString(chunks); return false; } } } return false; } MATCHER_P2(HasBriefComment, name, briefComment, std::string(negation ? "hasn't" : "has") + " completion of name " + PrintToString(name) + " with the brief comment " + PrintToString(briefComment)) { ::CodeCompletionsExtractor &extractor = const_cast<::CodeCompletionsExtractor&>(arg); while (extractor.next()) { if (extractor.currentCodeCompletion().text == name) { if (extractor.currentCodeCompletion().briefComment == briefComment) { return true; } else if (!extractor.peek(name)) { *result_listener << "briefComment is " << PrintToString(arg.currentCodeCompletion().briefComment) << " and not " << PrintToString(briefComment); return false; } } } return false; } const Utf8String unsavedFileContent(const char *unsavedFilePath) { QFile unsavedFileContentFile(QString::fromUtf8(unsavedFilePath)); bool isOpen = unsavedFileContentFile.open(QIODevice::ReadOnly | QIODevice::Text); if (!isOpen) ADD_FAILURE() << "File with the unsaved content cannot be opened!"; return Utf8String::fromByteArray(unsavedFileContentFile.readAll()); } const ClangBackEnd::FileContainer unsavedDataFileContainer(const char *filePath, const char *unsavedFilePath) { return ClangBackEnd::FileContainer(Utf8String::fromUtf8(filePath), unsavedFileContent(unsavedFilePath), true); } class CodeCompletionsExtractor : public ::testing::Test { protected: ClangCodeCompleteResults getResults(const Document &document, uint line, uint column = 1, bool needsReparse = false); protected: ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::Documents documents{unsavedFiles}; Utf8StringVector compilationArguments{UnitTest::addPlatformArguments()}; Document functionDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), compilationArguments, {}, documents}; Document functionOverloadDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_functionoverload.cpp"), compilationArguments, {}, documents}; Document variableDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp"), compilationArguments, {}, documents}; Document classDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_class.cpp"), compilationArguments, {}, documents}; Document namespaceDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_namespace.cpp"), compilationArguments, {}, documents}; Document enumerationDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_enumeration.cpp"), compilationArguments, {}, documents}; Document constructorDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_constructor.cpp"), compilationArguments, {}, documents}; Document constructorMemberInitDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_constructorMemberInitialization.cpp"), compilationArguments, {}, documents}; Document briefCommentDocument{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_brief_comment.cpp"), compilationArguments, {}, documents}; }; using CodeCompletionsExtractorSlowTest = CodeCompletionsExtractor; TEST_F(CodeCompletionsExtractorSlowTest, Function) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Function"), CodeCompletion::FunctionCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, TemplateFunction) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateFunction"), CodeCompletion::TemplateFunctionCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Variable) { ClangCodeCompleteResults completeResults(getResults(variableDocument, 4)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Var"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, NonTypeTemplateParameter) { ClangCodeCompleteResults completeResults(getResults(variableDocument, 25, 19)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NonTypeTemplateParameter"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, VariableReference) { ClangCodeCompleteResults completeResults(getResults(variableDocument, 12)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Var"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Parameter) { ClangCodeCompleteResults completeResults(getResults(variableDocument, 4)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Parameter"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Field) { ClangCodeCompleteResults completeResults(getResults(variableDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Field"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Class) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Class"), CodeCompletion::ClassCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Struct) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Struct"), CodeCompletion::ClassCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Union) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Union"), CodeCompletion::ClassCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Typedef) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TypeDef"), CodeCompletion::TypeAliasCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, UsingAsTypeAlias) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("UsingClass"), CodeCompletion::TypeAliasCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, TemplateTypeParameter) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateTypeParameter"), CodeCompletion::ClassCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, TemplateClass) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateClass"), CodeCompletion::TemplateClassCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, TemplateTemplateParameter) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateTemplateParameter"), CodeCompletion::TemplateClassCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, ClassTemplatePartialSpecialization) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("ClassTemplatePartialSpecialization"), CodeCompletion::TemplateClassCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Namespace) { ClangCodeCompleteResults completeResults(getResults(namespaceDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(namespaceDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Namespace"), CodeCompletion::NamespaceCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, NamespaceAlias) { ClangCodeCompleteResults completeResults(getResults(namespaceDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(namespaceDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NamespaceAlias"), CodeCompletion::NamespaceCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Enumeration) { ClangCodeCompleteResults completeResults(getResults(enumerationDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(enumerationDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Enumeration"), CodeCompletion::EnumerationCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Enumerator) { ClangCodeCompleteResults completeResults(getResults(enumerationDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(enumerationDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Enumerator"), CodeCompletion::EnumeratorCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Constructor) { ClangCodeCompleteResults completeResults(getResults(constructorDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(constructorDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Constructor"), CodeCompletion::ConstructorCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, ConstructorMemberInitializer) { ClangCodeCompleteResults completeResults(getResults(constructorMemberInitDocument, 2, 18)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(constructorDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("member"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Destructor) { ClangCodeCompleteResults completeResults(getResults(constructorDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(constructorDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("~Constructor"), CodeCompletion::DestructorCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Method) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Method"), CodeCompletion::FunctionDefinitionCompletionKind, CodeCompletion::Available)); ASSERT_FALSE(extractor.currentCodeCompletion().hasParameters); } TEST_F(CodeCompletionsExtractorSlowTest, MethodWithParameters) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("MethodWithParameters"), CodeCompletion::FunctionDefinitionCompletionKind, CodeCompletion::Available)); ASSERT_TRUE(extractor.currentCodeCompletion().hasParameters); } TEST_F(CodeCompletionsExtractorSlowTest, Slot) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Slot"), CodeCompletion::SlotCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, Signal) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Signal"), CodeCompletion::SignalCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, MacroDefinition) { ClangCodeCompleteResults completeResults(getResults(variableDocument, 35)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("MacroDefinition"), CodeCompletion::PreProcessorCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, FunctionMacro) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("FunctionMacro"), CodeCompletion::FunctionCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, IntKeyword) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("int"), CodeCompletion::KeywordCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, SwitchKeyword) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("switch"), CodeCompletion::KeywordCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, ClassKeyword) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("class"), CodeCompletion::KeywordCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, DeprecatedFunction) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("DeprecatedFunction"), CodeCompletion::FunctionDefinitionCompletionKind, CodeCompletion::Deprecated)); } TEST_F(CodeCompletionsExtractorSlowTest, NotAccessibleFunction) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NotAccessibleFunction"), CodeCompletion::FunctionDefinitionCompletionKind, CodeCompletion::NotAccessible)); } TEST_F(CodeCompletionsExtractorSlowTest, NotAvailableFunction) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NotAvailableFunction"), CodeCompletion::FunctionDefinitionCompletionKind, CodeCompletion::NotAvailable)); } TEST_F(CodeCompletionsExtractorSlowTest, UnsavedFile) { Document document(Utf8String::fromUtf8(TESTDATA_DIR "/complete_extractor_function.cpp"), compilationArguments, {}, documents); unsavedFiles.createOrUpdate( {unsavedDataFileContainer(TESTDATA_DIR "/complete_extractor_function.cpp", TESTDATA_DIR "/complete_extractor_function_unsaved.cpp")}); ClangCodeCompleteResults completeResults(getResults(document, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(document.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Method2"), CodeCompletion::FunctionDefinitionCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, ChangeUnsavedFile) { Document document(Utf8String::fromUtf8(TESTDATA_DIR "/complete_extractor_function.cpp"), compilationArguments, {}, documents); unsavedFiles.createOrUpdate( {unsavedDataFileContainer(TESTDATA_DIR "/complete_extractor_function.cpp", TESTDATA_DIR "/complete_extractor_function_unsaved.cpp")}); ClangCodeCompleteResults completeResults(getResults(document, 20)); unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp", TESTDATA_DIR"/complete_extractor_function_unsaved_2.cpp")}); completeResults = getResults(document, 20); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(document.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Method3"), CodeCompletion::FunctionDefinitionCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, ArgumentDefinition) { Document variableDocument{Utf8StringLiteral(TESTDATA_DIR "/complete_extractor_variable.cpp"), {Utf8StringLiteral("-DArgumentDefinition"), Utf8StringLiteral("-std=gnu++14")}, {}, documents}; ClangCodeCompleteResults completeResults(getResults(variableDocument, 35)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("ArgumentDefinitionVariable"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available)); } TEST_F(CodeCompletionsExtractorSlowTest, NoArgumentDefinition) { Document variableDocument{Utf8StringLiteral(TESTDATA_DIR "/complete_extractor_variable.cpp"), {Utf8StringLiteral("-std=gnu++14")}, {}, documents}; ClangCodeCompleteResults completeResults(getResults(variableDocument, 35)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, Not(HasCompletion(Utf8StringLiteral("ArgumentDefinitionVariable"), CodeCompletion::VariableCompletionKind, CodeCompletion::Available))); } TEST_F(CodeCompletionsExtractorSlowTest, CompletionChunksFunction) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Function"), CodeCompletionChunks({{CodeCompletionChunk::ResultType, Utf8StringLiteral("void")}, {CodeCompletionChunk::TypedText, Utf8StringLiteral("Function")}, {CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")}, {CodeCompletionChunk::RightParen, Utf8StringLiteral(")")}}))); } TEST_F(CodeCompletionsExtractorSlowTest, CompletionChunksFunctionWithOptionalChunks) { ClangCodeCompleteResults completeResults(getResults(functionDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("FunctionWithOptional"), CodeCompletionChunks({{CodeCompletionChunk::ResultType, Utf8StringLiteral("void")}, {CodeCompletionChunk::TypedText, Utf8StringLiteral("FunctionWithOptional")}, {CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")}, {CodeCompletionChunk::Placeholder, Utf8StringLiteral("int x")}, {CodeCompletionChunk::Comma, Utf8StringLiteral(", "), true}, {CodeCompletionChunk::Placeholder, Utf8StringLiteral("char y = 1"), true}, {CodeCompletionChunk::Comma, Utf8StringLiteral(", "), true}, {CodeCompletionChunk::Placeholder, Utf8StringLiteral("int z = 5"), true}, {CodeCompletionChunk::RightParen, Utf8StringLiteral(")")}}))); } TEST_F(CodeCompletionsExtractorSlowTest, CompletionChunksField) { ClangCodeCompleteResults completeResults(getResults(variableDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(variableDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Field"), CodeCompletionChunks({{CodeCompletionChunk::ResultType, Utf8StringLiteral("int")}, {CodeCompletionChunk::TypedText, Utf8StringLiteral("Field")}}))); } TEST_F(CodeCompletionsExtractorSlowTest, CompletionChunksEnumerator) { ClangCodeCompleteResults completeResults(getResults(enumerationDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(enumerationDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Enumerator"), CodeCompletionChunks({{CodeCompletionChunk::ResultType, Utf8StringLiteral("Enumeration")}, {CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumerator")}}))); } TEST_F(CodeCompletionsExtractorSlowTest, CompletionChunksEnumeration) { ClangCodeCompleteResults completeResults(getResults(enumerationDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(enumerationDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Enumeration"), CodeCompletionChunks({{CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumeration")}}))); } TEST_F(CodeCompletionsExtractorSlowTest, CompletionChunksClass) { ClangCodeCompleteResults completeResults(getResults(classDocument, 20)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(classDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Class"), CodeCompletionChunks({{CodeCompletionChunk::TypedText, Utf8StringLiteral("Class")}}))); } TEST_F(CodeCompletionsExtractorSlowTest, BriefComment) { ClangCodeCompleteResults completeResults(getResults(briefCommentDocument, 10, 1, /*needsReparse=*/ true)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(briefCommentDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasBriefComment(Utf8StringLiteral("BriefComment"), Utf8StringLiteral("A brief comment"))); } TEST_F(CodeCompletionsExtractorSlowTest, OverloadCandidate) { ClangCodeCompleteResults completeResults(getResults(functionOverloadDocument, 8, 13)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(functionOverloadDocument.filePath()), completeResults.data()); ASSERT_THAT(extractor, HasCompletionChunks(Utf8String(), CodeCompletionChunks({ {CodeCompletionChunk::Text, Utf8StringLiteral("Foo")}, {CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")}, {CodeCompletionChunk::CurrentParameter, Utf8StringLiteral("const Foo &foo")}, {CodeCompletionChunk::RightParen, Utf8StringLiteral(")")}, }))); } TEST_F(CodeCompletionsExtractorSlowTest, ExtractAll) { ClangCodeCompleteResults completeResults(getResults(constructorDocument, 25)); ::CodeCompletionsExtractor extractor( unsavedFiles.unsavedFile(constructorDocument.filePath()), completeResults.data()); auto codeCompletions = extractor.extractAll(false); ASSERT_THAT(codeCompletions.empty(), false); } ClangCodeCompleteResults CodeCompletionsExtractor::getResults(const Document &document, uint line, uint column, bool needsReparse) { document.parse(); if (needsReparse) document.reparse(); const Utf8String nativeFilePath = FilePath::toNativeSeparators(document.filePath()); UnsavedFilesShallowArguments unsaved = unsavedFiles.shallowArguments(); return ClangCodeCompleteResults(clang_codeCompleteAt(document.translationUnit().cxTranslationUnit(), nativeFilePath.constData(), line, column, unsaved.data(), unsaved.count(), CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns | CXCodeComplete_IncludeBriefComments)); } }