usaxena95 created this revision.
Herald added subscribers: cfe-commits, kadircet, arphaman.
Herald added a project: clang.
usaxena95 requested review of this revision.
Herald added subscribers: MaskRay, ilya-biryukov.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D91626

Files:
  clang-tools-extra/clangd/ClangdLSPServer.cpp
  clang-tools-extra/clangd/ClangdLSPServer.h
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/XRefs.h
  clang-tools-extra/clangd/unittests/XRefsTests.cpp

Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -41,6 +41,7 @@
 using ::testing::Eq;
 using ::testing::IsEmpty;
 using ::testing::Matcher;
+using ::testing::Not;
 using ::testing::UnorderedElementsAre;
 using ::testing::UnorderedElementsAreArray;
 
@@ -1161,7 +1162,7 @@
     )cpp",
   };
 
-  for (const auto* Case : Tests) {
+  for (const auto *Case : Tests) {
     SCOPED_TRACE(Case);
     auto T = Annotations(Case);
     auto AST = TestTU::withCode(T.code()).build();
@@ -1464,6 +1465,69 @@
   }
 }
 
+// TEST(FindImplementations, Inheritance) {
+//   llvm::StringRef Test = R"cpp(
+//     struct Base {
+//       virtual void F$1^oo();
+//     };
+//     struct Sub1 : Base {
+//       void $1[[Foo]]() override;
+//       virtual void Bar();
+//     };
+//     struct Sub2 : Base {
+//       void $1[[Foo]]() override;
+//       virtual void Baz();
+//     };
+//     struct Sub12: Sub1, Sub2 {
+//       void $1[[Foo]]() override;
+//       void Bar() override;
+//       void Baz() override;
+//     };
+
+//     void FromReference() {
+//       Base* B;
+//       B->Fo$1^o();
+//     }
+//   )cpp";
+
+//   Annotations Code(Test);
+//   auto TU = TestTU::withCode(Code.code());
+//   auto AST = TU.build();
+
+//   std::vector<Matcher<Location>> ExpectedLocations;
+//   for (const auto &R : Code.ranges("1"))
+//     ExpectedLocations.push_back(RangeIs(R));
+//   for (const auto &Point : Code.points("1")) {
+//     EXPECT_THAT(findImplementations(AST, Point, TU.index().get()).References,
+//                 UnorderedElementsAreArray(ExpectedLocations))
+//         << Test << " at" << Point;
+//   }
+// }
+
+// TEST(FindImplementations, BaseTemplateDoesNotWork) {
+//   std::string Test = R"cpp(
+//     template <typename T>
+//     class Base {
+//       virtual void f^oo();
+//     };
+//     class Sub : public Base<int> {
+//       void [[foo]]() override;
+//     };
+//   )cpp";
+//   Annotations Code(Test);
+//   auto TU = TestTU::withCode(Code.code());
+//   auto AST = TU.build();
+
+//   std::vector<Matcher<Location>> ExpectedLocations;
+//   for (const auto &R : Code.ranges())
+//     ExpectedLocations.push_back(RangeIs(R));
+//   // FIXME: No implementations for templated virtual functions.
+//   EXPECT_THAT(
+//       findImplementations(AST, Code.point(), TU.index().get()).References,
+//       Not(UnorderedElementsAreArray(ExpectedLocations)))
+//       << Test;
+// }
+
 TEST(FindReferences, WithinAST) {
   const char *Tests[] = {
       R"cpp(// Local variable
Index: clang-tools-extra/clangd/XRefs.h
===================================================================
--- clang-tools-extra/clangd/XRefs.h
+++ clang-tools-extra/clangd/XRefs.h
@@ -82,6 +82,11 @@
   std::vector<Location> References;
   bool HasMore = false;
 };
+
+/// Returns implementations of the virtual function at a specified \p Pos.
+ReferencesResult findImplementations(ParsedAST &AST, Position Pos,
+                                     const SymbolIndex *Index = nullptr);
+
 /// Returns references of the symbol at a specified \p Pos.
 /// \p Limit limits the number of results returned (0 means no limit).
 ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -1124,6 +1124,40 @@
   return Result;
 }
 
+ReferencesResult findImplementations(ParsedAST &AST, Position Pos,
+                                     const SymbolIndex *Index) {
+  ReferencesResult Results;
+  // We rely on index to find the implementations in subclasses.
+  if (!Index)
+    return Results;
+  const SourceManager &SM = AST.getSourceManager();
+  auto MainFilePath =
+      getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
+  if (!MainFilePath) {
+    elog("Failed to get a path for the main file, so no implementations.");
+    return Results;
+  }
+  auto CurLoc = sourceLocationInMainFile(SM, Pos);
+  DeclRelationSet Relations =
+      DeclRelation::TemplatePattern | DeclRelation::Alias;
+  std::vector<const NamedDecl *> Decls =
+      getDeclAtPosition(AST, *CurLoc, Relations);
+
+  const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(Decls[0]);
+  if (!CMD)
+    return Results;
+
+  SymbolID ID = getSymbolID(CMD);
+  RelationsRequest Req;
+  Req.Subjects.insert(ID);
+  Req.Predicate = RelationKind::OverridenBy;
+  Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {
+    if (auto Loc = symbolToLocation(Object, *MainFilePath))
+      Results.References.push_back(*Loc);
+  });
+  return Results;
+}
+
 ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
                                 const SymbolIndex *Index) {
   if (!Limit)
Index: clang-tools-extra/clangd/Protocol.h
===================================================================
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -1402,6 +1402,10 @@
 };
 bool fromJSON(const llvm::json::Value &, ReferenceParams &, llvm::json::Path);
 
+struct ImplementationParams : public TextDocumentPositionParams {};
+bool fromJSON(const llvm::json::Value &, ImplementationParams &,
+              llvm::json::Path);
+
 /// Clangd extension: indicates the current state of the file in clangd,
 /// sent from server via the `textDocument/clangd.fileStatus` notification.
 struct FileStatus {
Index: clang-tools-extra/clangd/Protocol.cpp
===================================================================
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -1209,6 +1209,12 @@
   return fromJSON(Params, Base, P);
 }
 
+bool fromJSON(const llvm::json::Value &Params, ImplementationParams &R,
+              llvm::json::Path P) {
+  TextDocumentPositionParams &Base = R;
+  return fromJSON(Params, Base, P);
+}
+
 static const char *toString(OffsetEncoding OE) {
   switch (OE) {
   case OffsetEncoding::UTF8:
Index: clang-tools-extra/clangd/ClangdServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdServer.h
+++ clang-tools-extra/clangd/ClangdServer.h
@@ -253,6 +253,10 @@
   /// Retrieve ranges that can be used to fold code within the specified file.
   void foldingRanges(StringRef File, Callback<std::vector<FoldingRange>> CB);
 
+  /// Retrieve implementations for virtual method.
+  void findImplementations(PathRef File, Position Pos,
+                           Callback<ReferencesResult> CB);
+
   /// Retrieve locations for symbol references.
   void findReferences(PathRef File, Position Pos, uint32_t Limit,
                       Callback<ReferencesResult> CB);
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -717,6 +717,18 @@
                            TUScheduler::InvalidateOnUpdate);
 }
 
+void ClangdServer::findImplementations(PathRef File, Position Pos,
+                                       Callback<ReferencesResult> CB) {
+  auto Action = [Pos, CB = std::move(CB),
+                 this](llvm::Expected<InputsAndAST> InpAST) mutable {
+    if (!InpAST)
+      return CB(InpAST.takeError());
+    CB(clangd::findImplementations(InpAST->AST, Pos, Index));
+  };
+
+  WorkScheduler.runWithAST("Implementations", File, std::move(Action));
+}
+
 void ClangdServer::findReferences(PathRef File, Position Pos, uint32_t Limit,
                                   Callback<ReferencesResult> CB) {
   auto Action = [Pos, Limit, CB = std::move(CB),
Index: clang-tools-extra/clangd/ClangdLSPServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.h
+++ clang-tools-extra/clangd/ClangdLSPServer.h
@@ -114,6 +114,8 @@
                          Callback<std::vector<Location>>);
   void onGoToDefinition(const TextDocumentPositionParams &,
                         Callback<std::vector<Location>>);
+  void onImplementation(const ImplementationParams &,
+                        Callback<std::vector<Location>>);
   void onReference(const ReferenceParams &, Callback<std::vector<Location>>);
   void onSwitchSourceHeader(const TextDocumentIdentifier &,
                             Callback<llvm::Optional<URIForFile>>);
Index: clang-tools-extra/clangd/ClangdLSPServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -612,6 +612,7 @@
             {"selectionRangeProvider", true},
             {"documentSymbolProvider", true},
             {"workspaceSymbolProvider", true},
+            {"implementationProvider", true},
             {"referencesProvider", true},
             {"executeCommandProvider",
              llvm::json::Object{
@@ -1288,6 +1289,18 @@
                          });
 }
 
+void ClangdLSPServer::onImplementation(const ImplementationParams &Params,
+                                       Callback<std::vector<Location>> Reply) {
+  Server->findImplementations(
+      Params.textDocument.uri.file(), Params.position,
+      [Reply =
+           std::move(Reply)](llvm::Expected<ReferencesResult> Impls) mutable {
+        if (!Impls)
+          return Reply(Impls.takeError());
+        return Reply(std::move(Impls->References));
+      });
+}
+
 void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params,
                                    Callback<std::vector<SymbolDetails>> Reply) {
   Server->symbolInfo(Params.textDocument.uri.file(), Params.position,
@@ -1424,6 +1437,7 @@
   MsgHandler->bind("textDocument/definition", &ClangdLSPServer::onGoToDefinition);
   MsgHandler->bind("textDocument/declaration", &ClangdLSPServer::onGoToDeclaration);
   MsgHandler->bind("textDocument/references", &ClangdLSPServer::onReference);
+  MsgHandler->bind("textDocument/implementation", &ClangdLSPServer::onImplementation);
   MsgHandler->bind("textDocument/switchSourceHeader", &ClangdLSPServer::onSwitchSourceHeader);
   MsgHandler->bind("textDocument/prepareRename", &ClangdLSPServer::onPrepareRename);
   MsgHandler->bind("textDocument/rename", &ClangdLSPServer::onRename);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to