adamcz created this revision. Herald added subscribers: usaxena95, kadircet, arphaman. adamcz requested review of this revision. Herald added a project: clang-tools-extra. Herald added a subscriber: cfe-commits.
Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D112628 Files: clang-tools-extra/clangd/CodeCompletionStrings.cpp clang-tools-extra/clangd/CodeCompletionStrings.h clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/Hover.h clang-tools-extra/clangd/SourceCode.cpp clang-tools-extra/clangd/SourceCode.h clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/unittests/HoverTests.cpp
Index: clang-tools-extra/clangd/unittests/HoverTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/HoverTests.cpp +++ clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -2517,6 +2517,77 @@ } } +TEST(Hover, DocLocation) { + const std::string Filename = "main.cpp"; + const std::string HeaderFilename = "header.h"; + + struct { + const char *const Code; + const std::function<void(HoverInfo &)> ExpectedBuilder; + } Cases[] = { + { + R"cpp( + // main-doc + void main_file_fun(); + + void foo() { m^ain_file_fun(); } + )cpp", + [&](HoverInfo &HI) { + HI.Documentation = "main-doc"; + HI.DocumentationLocation.range.start.line = 1; + HI.DocumentationLocation.range.start.character = 6; + HI.DocumentationLocation.range.end.line = 1; + HI.DocumentationLocation.range.end.character = 17; + HI.DocumentationLocation.uri = + URIForFile::canonicalize(testPath(Filename), Filename); + }}, + { + R"cpp( + void foo() { hea^der_fun(); } + )cpp", + [&](HoverInfo &HI) { + HI.Documentation = "main-doc"; + HI.DocumentationLocation.range.start.line = 1; + HI.DocumentationLocation.range.start.character = 2; + HI.DocumentationLocation.range.end.line = 1; + HI.DocumentationLocation.range.end.character = 8; + HI.DocumentationLocation.uri = URIForFile::canonicalize( + testPath(HeaderFilename), HeaderFilename); + }}, + }; + + const std::string Header = R"cpp( + // doc + void header_fun(); + )cpp"; + + for (const auto &Case : Cases) { + SCOPED_TRACE(Case.Code); + + Annotations T(Case.Code); + TestTU TU = TestTU::withCode(T.code()); + TU.HeaderCode = Header; + TU.Filename = Filename; + TU.HeaderFilename = HeaderFilename; + + auto Index = std::make_unique<FileIndex>(); + TU.preamble([&](ASTContext &Ctx, std::shared_ptr<Preprocessor> PP, + const CanonicalIncludes &CanonIncludes) { + Index->updatePreamble(TU.Filename, "null", Ctx, PP, CanonIncludes); + }); + + auto AST = TU.build(); + auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get()); + ASSERT_TRUE(H); + + HoverInfo Expected; + Case.ExpectedBuilder(Expected); + + EXPECT_EQ(H->Documentation, Expected.Documentation); + EXPECT_EQ(H->DocumentationLocation, Expected.DocumentationLocation); + } +} + TEST(Hover, NoCrash) { Annotations T(R"cpp( /* error-ok */ Index: clang-tools-extra/clangd/XRefs.cpp =================================================================== --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -210,29 +210,6 @@ return Result; } -// Expects Loc to be a SpellingLocation, will bail out otherwise as it can't -// figure out a filename. -llvm::Optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc, - llvm::StringRef TUPath) { - const auto &SM = AST.getSourceManager(); - const FileEntry *F = SM.getFileEntryForID(SM.getFileID(Loc)); - if (!F) - return None; - auto FilePath = getCanonicalPath(F, SM); - if (!FilePath) { - log("failed to get path!"); - return None; - } - Location L; - L.uri = URIForFile::canonicalize(*FilePath, TUPath); - // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens - // outside the main file. - auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts()); - L.range = halfOpenToRange( - SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen))); - return L; -} - // Treat #included files as symbols, to enable go-to-definition on them. llvm::Optional<LocatedSymbol> locateFileReferent(const Position &Pos, ParsedAST &AST, Index: clang-tools-extra/clangd/SourceCode.h =================================================================== --- clang-tools-extra/clangd/SourceCode.h +++ clang-tools-extra/clangd/SourceCode.h @@ -16,6 +16,7 @@ #include "Protocol.h" #include "support/Context.h" #include "support/ThreadsafeFS.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" @@ -324,6 +325,11 @@ /// Returns true if the given location is in a generated protobuf file. bool isProtoFile(SourceLocation Loc, const SourceManager &SourceMgr); +// Expects Loc to be a SpellingLocation, will bail out otherwise as it can't +// figure out a filename. +llvm::Optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc, + llvm::StringRef TUPath); + } // namespace clangd } // namespace clang #endif Index: clang-tools-extra/clangd/SourceCode.cpp =================================================================== --- clang-tools-extra/clangd/SourceCode.cpp +++ clang-tools-extra/clangd/SourceCode.cpp @@ -1180,5 +1180,26 @@ return SM.getBufferData(FID).startswith(PROTO_HEADER_COMMENT); } +llvm::Optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc, + llvm::StringRef TUPath) { + const auto &SM = AST.getSourceManager(); + const FileEntry *F = SM.getFileEntryForID(SM.getFileID(Loc)); + if (!F) + return None; + auto FilePath = getCanonicalPath(F, SM); + if (!FilePath) { + log("failed to get path!"); + return None; + } + Location L; + L.uri = URIForFile::canonicalize(*FilePath, TUPath); + // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens + // outside the main file. + auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts()); + L.range = halfOpenToRange( + SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen))); + return L; +} + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/Hover.h =================================================================== --- clang-tools-extra/clangd/Hover.h +++ clang-tools-extra/clangd/Hover.h @@ -56,6 +56,9 @@ llvm::Optional<Range> SymRange; index::SymbolKind Kind = index::SymbolKind::Unknown; std::string Documentation; + // Location of the documentation in the source code, if any. This can be used + // to linkify that part of hover card or check permissions. + Location DocumentationLocation; /// Source code containing the definition of the symbol. std::string Definition; const char *DefinitionLanguage = "cpp"; Index: clang-tools-extra/clangd/Hover.cpp =================================================================== --- clang-tools-extra/clangd/Hover.cpp +++ clang-tools-extra/clangd/Hover.cpp @@ -302,6 +302,8 @@ LookupRequest Req; Req.IDs.insert(ID); Index->lookup(Req, [&](const Symbol &S) { + // FIXME: We should fill Hover.DocumentationLocation as well, but currently + // we do not have that information in the index. Hover.Documentation = std::string(S.Documentation); }); } @@ -543,6 +545,25 @@ return ""; } +void addDocumentationToHoverInfo(const NamedDecl *D, const ASTContext &ASTCtx, + HoverInfo &HI) { + const auto &SM = ASTCtx.getSourceManager(); + + SourceRange DocumentationRange; + HI.Documentation = getDeclComment(ASTCtx, *D, &DocumentationRange); + + if (DocumentationRange.isValid()) { + const auto MainFilePath = + getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM); + if (MainFilePath) { + const auto Loc = + makeLocation(ASTCtx, DocumentationRange.getBegin(), *MainFilePath); + if (Loc) + HI.DocumentationLocation = *Loc; + } + } +} + /// Generate a \p Hover object given the declaration \p D. HoverInfo getHoverContents(const NamedDecl *D, const PrintingPolicy &PP, const SymbolIndex *Index) { @@ -559,7 +580,7 @@ HI.Name = printName(Ctx, *D); const auto *CommentD = getDeclForComment(D); - HI.Documentation = getDeclComment(Ctx, *CommentD); + addDocumentationToHoverInfo(CommentD, Ctx, HI); enhanceFromIndex(HI, *CommentD, Index); if (HI.Documentation.empty()) HI.Documentation = synthesizeDocumentation(D); @@ -673,7 +694,7 @@ if (const auto *D = QT->getAsTagDecl()) { const auto *CommentD = getDeclForComment(D); - HI.Documentation = getDeclComment(ASTCtx, *CommentD); + addDocumentationToHoverInfo(CommentD, ASTCtx, HI); enhanceFromIndex(HI, *CommentD, Index); } } Index: clang-tools-extra/clangd/CodeCompletionStrings.h =================================================================== --- clang-tools-extra/clangd/CodeCompletionStrings.h +++ clang-tools-extra/clangd/CodeCompletionStrings.h @@ -32,8 +32,11 @@ const CodeCompletionResult &Result, bool CommentsFromHeaders); -/// Similar to getDocComment, but returns the comment for a NamedDecl. -std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &D); +/// Similar to getDocComment, but returns the comment for a NamedDecl. The +/// optional CommentRange argument is set to the location of the returned +/// comment. +std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &D, + SourceRange *CommentRange = nullptr); /// Formats the signature for an item, as a display string and snippet. /// e.g. for const_reference std::vector<T>::at(size_type) const, this returns: Index: clang-tools-extra/clangd/CodeCompletionStrings.cpp =================================================================== --- clang-tools-extra/clangd/CodeCompletionStrings.cpp +++ clang-tools-extra/clangd/CodeCompletionStrings.cpp @@ -71,7 +71,8 @@ : ""; } -std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl) { +std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl, + SourceRange *CommentRange) { if (isa<NamespaceDecl>(Decl)) { // Namespaces often have too many redecls for any particular redecl comment // to be useful. Moreover, we often confuse file headers or generated @@ -92,6 +93,9 @@ // Clang requires source to be UTF-8, but doesn't enforce this in comments. if (!llvm::json::isUTF8(Doc)) Doc = llvm::json::fixUTF8(Doc); + if (CommentRange) { + *CommentRange = RC->getSourceRange(); + } return Doc; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits