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
  • [PATCH] D112628: NOT REA... Adam Czachorowski via Phabricator via cfe-commits

Reply via email to