Nebiroth updated this revision to Diff 109566.
Nebiroth marked 7 inline comments as done.
Nebiroth added a comment.

[clangd] LSP extension to switch between source/header file


https://reviews.llvm.org/D36150

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/ProtocolHandlers.cpp
  clangd/ProtocolHandlers.h

Index: clangd/ProtocolHandlers.h
===================================================================
--- clangd/ProtocolHandlers.h
+++ clangd/ProtocolHandlers.h
@@ -48,6 +48,8 @@
                             JSONOutput &Out) = 0;
   virtual void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
                             JSONOutput &Out) = 0;
+  virtual void onSwitchSourceHeader(TextDocumentIdentifier Params, StringRef ID,
+                            JSONOutput &Out) = 0;
 };
 
 void regiterCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out,
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -204,6 +204,23 @@
   ProtocolCallbacks &Callbacks;
 };
 
+struct SwitchSourceHeaderHandler : Handler {
+  SwitchSourceHeaderHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+      : Handler(Output), Callbacks(Callbacks) {}
+
+  void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+    auto TDPP = TextDocumentIdentifier::parse(Params);
+    if (!TDPP) {
+      return;
+    }
+
+    Callbacks.onSwitchSourceHeader(*TDPP, ID, Output);
+  }
+
+private:
+  ProtocolCallbacks &Callbacks;
+};
+
 } // namespace
 
 void clangd::regiterCallbackHandlers(JSONRPCDispatcher &Dispatcher,
@@ -239,4 +256,7 @@
       llvm::make_unique<CompletionHandler>(Out, Callbacks));
   Dispatcher.registerHandler("textDocument/definition",
       llvm::make_unique<GotoDefinitionHandler>(Out, Callbacks));
+  Dispatcher.registerHandler(
+      "textDocument/switchSourceHeader",
+      llvm::make_unique<SwitchSourceHeaderHandler>(Out, Callbacks));
 }
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -182,6 +182,9 @@
   /// Get definition of symbol at a specified \p Line and \p Column in \p File.
   Tagged<std::vector<Location>> findDefinitions(PathRef File, Position Pos);
 
+  // Helper function to change from one header file to it's corresponding source file and vice versa
+  Path switchSourceHeader(PathRef path);
+
   /// Run formatting for \p Rng inside \p File.
   std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng);
   /// Run formatting for the whole \p File.
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -16,13 +16,15 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
 #include <future>
 
 using namespace clang;
 using namespace clang::clangd;
 
 namespace {
 
+
 std::vector<tooling::Replacement> formatCode(StringRef Code, StringRef Filename,
                                              ArrayRef<tooling::Range> Ranges) {
   // Call clang-format.
@@ -286,3 +288,86 @@
       });
   return make_tagged(std::move(Result), TaggedFS.Tag);
 }
+
+Path ClangdServer::switchSourceHeader(PathRef path) {
+
+  std::string DEFAULT_SOURCE_EXTENSIONS[] = { ".cpp", ".c", ".cc", ".cxx",
+    ".c++", ".C", ".m", ".mm" };  
+  std::string DEFAULT_HEADER_EXTENSIONS[] = { ".h", ".hh", ".hpp", ".hxx",
+    ".inc" };  
+
+  const int sourceSize = sizeof(DEFAULT_SOURCE_EXTENSIONS)/sizeof(DEFAULT_SOURCE_EXTENSIONS[0]);
+  const int headerSize = sizeof(DEFAULT_HEADER_EXTENSIONS)/sizeof(DEFAULT_HEADER_EXTENSIONS[0]);
+
+  std::string pathDataRef = std::string(path.data());
+  bool isSourceFile = false, foundExtension = false;
+  SmallString<128> NewPath;
+  int i = 0;
+
+  while (!foundExtension && i < sourceSize)
+  {
+    if (llvm::sys::path::extension(pathDataRef) == DEFAULT_SOURCE_EXTENSIONS[i])
+    {    
+      std::string fileExtension = std::string(DEFAULT_SOURCE_EXTENSIONS[i]);
+      NewPath = pathDataRef;
+      pathDataRef = pathDataRef.substr(0, (pathDataRef.length() - fileExtension.size()));
+      isSourceFile = true;
+      foundExtension = true;
+    }
+    i++;
+  }
+  i = 0;
+
+  if (!foundExtension)
+  {
+    while (!foundExtension && i < headerSize)
+    {
+      if (llvm::sys::path::extension(pathDataRef) == DEFAULT_HEADER_EXTENSIONS[i])
+      {    
+        std::string fileExtension = std::string(DEFAULT_HEADER_EXTENSIONS[i]);
+        NewPath = pathDataRef;
+        pathDataRef = pathDataRef.substr(0, (pathDataRef.length() - fileExtension.size()));
+        isSourceFile = false;
+        foundExtension = true;
+      }
+    i++;
+    }
+  }
+
+  std::string temp = std::string(pathDataRef);
+  SmallString<128> CurrentPath;
+  CurrentPath = temp;
+  bool done = false;
+  std::vector<std::string> EXTENSIONS_ARRAY;
+  
+  if (!isSourceFile)
+    EXTENSIONS_ARRAY.assign(DEFAULT_SOURCE_EXTENSIONS, DEFAULT_SOURCE_EXTENSIONS + sourceSize);
+  else
+    EXTENSIONS_ARRAY.assign(DEFAULT_HEADER_EXTENSIONS, DEFAULT_HEADER_EXTENSIONS + headerSize);
+
+  i = 0;   
+  while (!done && i < EXTENSIONS_ARRAY.size())
+  {      
+    std::string CurrentPathString = CurrentPath.str();   
+    std::string NewPathString = NewPath.str();
+    if (i == 0)    
+      CurrentPathString = pathDataRef.append(std::string(EXTENSIONS_ARRAY[i]));
+    else
+      CurrentPathString = CurrentPathString.append(std::string(EXTENSIONS_ARRAY[i]));
+    
+    std::string temp = CurrentPathString.substr(7, CurrentPathString.size());
+    FILE * file;
+    file = fopen(temp.c_str(), "r");
+    if (file)
+    {
+      done = true;
+      fclose(file);
+      llvm::sys::path::replace_extension(NewPath, EXTENSIONS_ARRAY[i]);
+      std::string returnValue = std::string(NewPath.str());
+      return Path("\"" + returnValue + "\"");
+    }
+    llvm::sys::path::replace_extension(CurrentPath, "");
+    CurrentPathString = CurrentPath.str();
+    i++;
+  }
+}
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -71,6 +71,8 @@
                     JSONOutput &Out) override;
   void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
                             JSONOutput &Out) override;
+  void onSwitchSourceHeader(TextDocumentIdentifier Params, StringRef ID,
+                    JSONOutput &Out) override;                          
 
 private:
   ClangdLSPServer &LangServer;
@@ -216,6 +218,17 @@
       R"(,"result":[)" + Locations + R"(]})");
 }
 
+void ClangdLSPServer::LSPProtocolCallbacks::onSwitchSourceHeader(
+    TextDocumentIdentifier Params, StringRef ID, JSONOutput &Out) {
+
+  PathRef ref = PathRef((Params.uri.uri).c_str());
+  Path result = LangServer.Server.switchSourceHeader(ref);
+
+    Out.writeMessage(
+        R"({"jsonrpc":"2.0","id":)" + ID.str() +
+        R"(,"result":)" + result + R"(})");
+}
+
 ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, bool RunSynchronously)
     : Out(Out), DiagConsumer(*this),
       Server(CDB, DiagConsumer, FSProvider, RunSynchronously) {}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to