Nebiroth updated this revision to Diff 111368.
Nebiroth marked 8 inline comments as done.
Nebiroth added a comment.

Fixed diff comments.


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 that returns a path to the corresponding source file when given a header 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
@@ -15,6 +15,7 @@
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 #include <future>
 
@@ -286,3 +287,82 @@
       });
   return make_tagged(std::move(Result), TaggedFS.Tag);
 }
+
+Path ClangdServer::switchSourceHeader(PathRef path) {
+
+  std::string DEFAULT_SOURCE_EXTENSIONS[] = {
+      ".cpp", ".c", ".cc", ".cxx", ".c++", ".m", ".mm",
+      ".CPP", ".C", ".CC", ".CXX", ".C++", ".M", ".MM"};
+  std::string DEFAULT_HEADER_EXTENSIONS[] = {
+      ".h", ".hh", ".hpp", ".hxx", ".inc", ".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);
+  bool isSourceFile = false, foundExtension = false;
+  SmallString<128> NewPath;
+  std::string *p;
+  p = std::find(DEFAULT_SOURCE_EXTENSIONS,
+                DEFAULT_SOURCE_EXTENSIONS + sourceSize,
+                llvm::sys::path::extension(path));
+  if (p != DEFAULT_SOURCE_EXTENSIONS + sourceSize) 
+  {
+    std::string fileExtension = *p;
+    NewPath = pathDataRef;
+    pathDataRef =
+        pathDataRef.substr(0, (pathDataRef.size() - fileExtension.size()));
+    isSourceFile = true;
+    foundExtension = true;
+  }
+
+  if (!foundExtension) {
+    p = std::find(DEFAULT_HEADER_EXTENSIONS,
+                  DEFAULT_HEADER_EXTENSIONS + headerSize,
+                  llvm::sys::path::extension(path));
+    if (p != DEFAULT_HEADER_EXTENSIONS + headerSize) {
+      std::string fileExtension = *p;
+      NewPath = pathDataRef;
+      pathDataRef =
+          pathDataRef.substr(0, (pathDataRef.size() - fileExtension.size()));
+      isSourceFile = false;
+      foundExtension = true;
+    }
+  }
+
+  SmallString<128> CurrentPath;
+  CurrentPath = std::string(pathDataRef);
+  bool done = false;
+  ArrayRef<std::string> ExtensionsArray;
+
+  if (!isSourceFile)
+    ExtensionsArray = DEFAULT_SOURCE_EXTENSIONS;
+  else
+    ExtensionsArray = DEFAULT_HEADER_EXTENSIONS;
+
+  int i = 0;
+  while (!done && i < ExtensionsArray.size()) {
+    std::string CurrentPathString = CurrentPath.str();
+    std::string NewPathString = NewPath.str();
+    if (i == 0)
+      CurrentPathString = std::string(pathDataRef).append(std::string(ExtensionsArray[i]));
+    else    
+      CurrentPathString = CurrentPathString.append(std::string(ExtensionsArray[i]));
+
+    FILE *file;    
+    auto test = FSProvider.getTaggedFileSystem(std::string(CurrentPathString));
+    bool fileExists = test.Value.get()->exists(std::string(CurrentPathString));
+    if (fileExists) {
+      done = true;
+      llvm::sys::path::replace_extension(NewPath, ExtensionsArray[i]);
+      std::string returnValue = "file://" + std::string(NewPath.str());
+      returnValue = URI::unparse(URI::fromUri(returnValue));
+      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,16 @@
       R"(,"result":[)" + Locations + R"(]})");
 }
 
+void ClangdLSPServer::LSPProtocolCallbacks::onSwitchSourceHeader(
+    TextDocumentIdentifier Params, StringRef ID, JSONOutput &Out) {
+
+  Path Result = LangServer.Server.switchSourceHeader(Params.uri.file);
+
+    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