diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -131,6 +131,13 @@ return Definition; } +const char *getMarkdownLanguage(const ASTContext &Ctx) { + const auto &LangOpts = Ctx.getLangOpts(); + if (LangOpts.ObjC && LangOpts.CPlusPlus) + return "objective-cpp"; + return LangOpts.ObjC ? "objective-c" : "cpp"; +} + std::string printType(QualType QT, const PrintingPolicy &PP) { // TypePrinter doesn't resolve decltypes, so resolve them here. // FIXME: This doesn't handle composite types that contain a decltype in them. @@ -593,6 +600,7 @@ } HI.Definition = printDefinition(D, PP); + HI.DefinitionLanguage = getMarkdownLanguage(Ctx); return HI; } @@ -622,10 +630,12 @@ if (!Invalid) { unsigned StartOffset = SM.getFileOffset(StartLoc); unsigned EndOffset = SM.getFileOffset(EndLoc); - if (EndOffset <= Buffer.size() && StartOffset < EndOffset) + if (EndOffset <= Buffer.size() && StartOffset < EndOffset) { HI.Definition = ("#define " + Buffer.substr(StartOffset, EndOffset - StartOffset)) .str(); + HI.DefinitionLanguage = getMarkdownLanguage(AST.getASTContext()); + } } } return HI; @@ -646,6 +656,7 @@ HoverInfo HI; HI.Name = "this"; HI.Definition = printType(PrettyThisType, PP); + HI.DefinitionLanguage = getMarkdownLanguage(ASTCtx); return HI; } @@ -670,6 +681,7 @@ enhanceFromIndex(HI, *CommentD, Index); } } + HI.DefinitionLanguage = getMarkdownLanguage(ASTCtx); return HI; } @@ -731,6 +743,7 @@ llvm::raw_string_ostream OS(HI.Definition); A->printPretty(OS, AST.getASTContext().getPrintingPolicy()); } + HI.DefinitionLanguage = getMarkdownLanguage(AST.getASTContext()); HI.Documentation = Attr::getDocumentation(A->getKind()).str(); return HI; } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -939,6 +939,42 @@ } } +TEST(Hover, DefinitionLanuage) { + struct { + const char *const Code; + const std::string ClangLanguageFlag; + const char *const ExpectedDefinitionLanguage; + } Cases[] = {{R"cpp( + void [[some^Global]]() {} + )cpp", + "", "cpp"}, + {R"cpp( + void [[some^Global]]() {} + )cpp", + "-xobjective-c++", "objective-cpp"}, + {R"cpp( + void [[some^Global]]() {} + )cpp", + "-xobjective-c", "objective-c"}}; + for (const auto &Case : Cases) { + SCOPED_TRACE(Case.Code); + + Annotations T(Case.Code); + TestTU TU = TestTU::withCode(T.code()); + if (!Case.ClangLanguageFlag.empty()) + TU.ExtraArgs.push_back(Case.ClangLanguageFlag); + // Types might be different depending on the target triplet, we chose a + // fixed one to make sure tests passes on different platform. + TU.ExtraArgs.push_back("--target=x86_64-pc-linux-gnu"); + auto AST = TU.build(); + + auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr); + ASSERT_TRUE(H); + + EXPECT_STREQ(H->DefinitionLanguage, Case.ExpectedDefinitionLanguage); + } +} + TEST(Hover, CallPassType) { const llvm::StringRef CodePrefix = R"cpp( class Base {};