Nebiroth updated this revision to Diff 114048.
Nebiroth added a comment.
Remove unintentional file addition
Updating D36150: [clangd] LSP extension to switch between source/header file
============================================================================
ll#
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,12 @@
/// Get definition of symbol at a specified \p Line and \p Column in \p File.
Tagged<std::vector<Location>> findDefinitions(PathRef File, Position Pos);
+ /// If an extension hasn't been found in the lowercase array, try with uppercase.
+ bool checkUpperCaseExtensions(StringRef BaseArray[], int ArraySize, StringRef PathExt);
+
+ /// Helper function that returns a path to the corresponding source file when given a header file and vice versa.
+ llvm::Optional<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,9 +15,11 @@
#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>
+using namespace llvm;
using namespace clang;
using namespace clang::clangd;
@@ -286,3 +288,84 @@
});
return make_tagged(std::move(Result), TaggedFS.Tag);
}
+
+
+bool ClangdServer::checkUpperCaseExtensions(StringRef BaseArray[], int ArraySize, StringRef PathExt)
+{
+ std::string UpperExtensions[ArraySize];
+ for(int i = 0; i < ArraySize; i++)
+ {
+ UpperExtensions[i] = BaseArray[i];
+ }
+ // Uppercase the whole array
+ for (std::string & s : UpperExtensions)
+ std::transform(s.begin(), s.end(), s.begin(),
+ [](unsigned char c) { return std::toupper(c); });
+
+ bool isUpperCase = false;
+ // Iterator such as std::begin won't work here so we use a standard loop
+ for(int i = 0; i < ArraySize; i++)
+ {
+ if (UpperExtensions[i] == PathExt.str())
+ {
+ isUpperCase = true;
+ }
+ }
+ return isUpperCase;
+}
+
+llvm::Optional<Path> ClangdServer::switchSourceHeader(PathRef Path) {
+
+ StringRef SourceExtensions[] = {".cpp", ".c", ".cc", ".cxx", ".c++", ".m", ".mm"};
+ StringRef HeaderExtensions[] = {".h", ".hh", ".hpp", ".hxx", ".inc"};
+
+ StringRef PathExt = llvm::sys::path::extension(Path);
+
+ // Lookup in a list of known extensions.
+ auto SourceIter = std::find(std::begin(SourceExtensions), std::end(SourceExtensions), PathExt);
+ bool IsSource = SourceIter != std::end(SourceExtensions);
+
+ if (!IsSource)
+ {
+ IsSource = checkUpperCaseExtensions(SourceExtensions, llvm::array_lengthof(SourceExtensions), PathExt);
+ }
+
+ auto HeaderIter = std::find(std::begin(HeaderExtensions), std::end(HeaderExtensions), PathExt);
+ bool IsHeader = HeaderIter != std::end(HeaderExtensions);
+
+ if (!IsHeader)
+ {
+ IsHeader = checkUpperCaseExtensions(HeaderExtensions, llvm::array_lengthof(HeaderExtensions), PathExt);
+ }
+
+ // We can only switch between extensions known extensions.
+ if (!IsSource && !IsHeader)
+ return llvm::None;
+
+ // Array to lookup extensions for the switch. An opposite of where original extension was found.
+ ArrayRef<StringRef> NewExts;
+ if (IsSource)
+ NewExts = HeaderExtensions;
+ else
+ NewExts = SourceExtensions;
+
+ // Storage for the new path.
+ SmallString<128> NewPath = StringRef(Path);
+
+ // Instance of vfs::FileSystem, used for file existence checks.
+ auto FS = FSProvider.getTaggedFileSystem(Path).Value;
+
+ // Loop through switched extension candidates.
+ for (StringRef NewExt : NewExts) {
+ llvm::sys::path::replace_extension(NewPath, NewExt);
+ if (FS->exists(NewPath))
+ return NewPath.str().str(); // First str() to convert from SmallString to StringRef, second to convert from StringRef to std::string
+
+ // Also check NewExt in upper-case, just in case.
+ llvm::sys::path::replace_extension(NewPath, NewExt.upper());
+ if (FS->exists(NewPath))
+ return NewPath.str().str();
+ }
+
+ return llvm::None;
+}
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,18 @@
R"(,"result":[)" + Locations + R"(]})");
}
+void ClangdLSPServer::LSPProtocolCallbacks::onSwitchSourceHeader(
+ TextDocumentIdentifier Params, StringRef ID, JSONOutput &Out) {
+
+ llvm::Optional<Path> Result = LangServer.Server.switchSourceHeader(Params.uri.file);
+ std::string test = "file://";
+ Path ResultString = "\"" + test + *Result + "\"";
+
+ Out.writeMessage(
+ R"({"jsonrpc":"2.0","id":)" + ID.str() +
+ R"(,"result":)" + ResultString + R"(})");
+}
+
ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, bool RunSynchronously)
: Out(Out), DiagConsumer(*this),
Server(CDB, DiagConsumer, FSProvider, RunSynchronously) {}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits