summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clangd/ClangdLSPServer.cpp3
-rw-r--r--clang-tools-extra/clangd/ClangdUnitStore.cpp11
-rw-r--r--clang-tools-extra/clangd/GlobalCompilationDatabase.cpp49
-rw-r--r--clang-tools-extra/clangd/GlobalCompilationDatabase.h8
-rw-r--r--clang-tools-extra/clangd/Protocol.cpp32
-rw-r--r--clang-tools-extra/clangd/Protocol.h9
-rw-r--r--clang-tools-extra/test/clangd/extra-flags.test22
7 files changed, 123 insertions, 11 deletions
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 1fd0e95aef4..e0489eb15b8 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -97,6 +97,9 @@ void ClangdLSPServer::LSPProtocolCallbacks::onShutdown(JSONOutput &Out) {
void ClangdLSPServer::LSPProtocolCallbacks::onDocumentDidOpen(
DidOpenTextDocumentParams Params, JSONOutput &Out) {
+ if (Params.metadata && !Params.metadata->extraFlags.empty())
+ LangServer.CDB.setExtraFlagsForFile(Params.textDocument.uri.file,
+ std::move(Params.metadata->extraFlags));
LangServer.Server.addDocument(Params.textDocument.uri.file,
Params.textDocument.text);
}
diff --git a/clang-tools-extra/clangd/ClangdUnitStore.cpp b/clang-tools-extra/clangd/ClangdUnitStore.cpp
index 56e6f547a8d..c892f9950a8 100644
--- a/clang-tools-extra/clangd/ClangdUnitStore.cpp
+++ b/clang-tools-extra/clangd/ClangdUnitStore.cpp
@@ -22,13 +22,12 @@ void ClangdUnitStore::removeUnitIfPresent(PathRef File) {
OpenedFiles.erase(It);
}
-std::vector<tooling::CompileCommand> ClangdUnitStore::getCompileCommands(GlobalCompilationDatabase &CDB, PathRef File) {
+std::vector<tooling::CompileCommand>
+ClangdUnitStore::getCompileCommands(GlobalCompilationDatabase &CDB,
+ PathRef File) {
std::vector<tooling::CompileCommand> Commands = CDB.getCompileCommands(File);
- if (Commands.empty()) {
+ if (Commands.empty())
// Add a fake command line if we know nothing.
- Commands.push_back(tooling::CompileCommand(
- llvm::sys::path::parent_path(File), llvm::sys::path::filename(File),
- {"clang", "-fsyntax-only", File.str()}, ""));
- }
+ Commands.push_back(getDefaultCompileCommand(File));
return Commands;
}
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index 91d77026293..9cf8572c257 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -12,17 +12,53 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
-using namespace clang::clangd;
-using namespace clang;
+namespace clang {
+namespace clangd {
+
+static void addExtraFlags(tooling::CompileCommand &Command,
+ const std::vector<std::string> &ExtraFlags) {
+ if (ExtraFlags.empty())
+ return;
+ assert(Command.CommandLine.size() >= 2 &&
+ "Expected a command line containing at least 2 arguments, the "
+ "compiler binary and the output file");
+ // The last argument of CommandLine is the name of the input file.
+ // Add ExtraFlags before it.
+ auto It = Command.CommandLine.end();
+ --It;
+ Command.CommandLine.insert(It, ExtraFlags.begin(), ExtraFlags.end());
+}
+
+tooling::CompileCommand getDefaultCompileCommand(PathRef File) {
+ std::vector<std::string> CommandLine{"clang", "-fsyntax-only", File.str()};
+ return tooling::CompileCommand(llvm::sys::path::parent_path(File),
+ llvm::sys::path::filename(File), CommandLine,
+ /*Output=*/"");
+}
std::vector<tooling::CompileCommand>
DirectoryBasedGlobalCompilationDatabase::getCompileCommands(PathRef File) {
std::vector<tooling::CompileCommand> Commands;
auto CDB = getCompilationDatabase(File);
- if (!CDB)
- return {};
- return CDB->getCompileCommands(File);
+ if (CDB)
+ Commands = CDB->getCompileCommands(File);
+ if (Commands.empty())
+ Commands.push_back(getDefaultCompileCommand(File));
+
+ auto It = ExtraFlagsForFile.find(File);
+ if (It != ExtraFlagsForFile.end()) {
+ // Append the user-specified flags to the compile commands.
+ for (tooling::CompileCommand &Command : Commands)
+ addExtraFlags(Command, It->second);
+ }
+
+ return Commands;
+}
+
+void DirectoryBasedGlobalCompilationDatabase::setExtraFlagsForFile(
+ PathRef File, std::vector<std::string> ExtraFlags) {
+ ExtraFlagsForFile[File] = std::move(ExtraFlags);
}
tooling::CompilationDatabase *
@@ -63,3 +99,6 @@ DirectoryBasedGlobalCompilationDatabase::getCompilationDatabase(PathRef File) {
// "\n");
return nullptr;
}
+
+} // namespace clangd
+} // namespace clang
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
index 933e566545b..36c130c3512 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -25,6 +25,9 @@ struct CompileCommand;
namespace clangd {
+/// Returns a default compile command to use for \p File.
+tooling::CompileCommand getDefaultCompileCommand(PathRef File);
+
/// Provides compilation arguments used for building ClangdUnit.
class GlobalCompilationDatabase {
public:
@@ -45,6 +48,8 @@ public:
std::vector<tooling::CompileCommand>
getCompileCommands(PathRef File) override;
+ void setExtraFlagsForFile(PathRef File, std::vector<std::string> ExtraFlags);
+
private:
tooling::CompilationDatabase *getCompilationDatabase(PathRef File);
@@ -53,6 +58,9 @@ private:
/// directories).
llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>>
CompilationDatabases;
+
+ /// Stores extra flags per file.
+ llvm::StringMap<std::vector<std::string>> ExtraFlagsForFile;
};
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 17618f3a1c3..c370e0db0b4 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -204,6 +204,33 @@ TextDocumentItem::parse(llvm::yaml::MappingNode *Params) {
return Result;
}
+llvm::Optional<Metadata> Metadata::parse(llvm::yaml::MappingNode *Params) {
+ Metadata Result;
+ for (auto &NextKeyValue : *Params) {
+ auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+ if (!KeyString)
+ return llvm::None;
+
+ llvm::SmallString<10> KeyStorage;
+ StringRef KeyValue = KeyString->getValue(KeyStorage);
+ auto *Value = NextKeyValue.getValue();
+
+ llvm::SmallString<10> Storage;
+ if (KeyValue == "extraFlags") {
+ auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
+ if (!Seq)
+ return llvm::None;
+ for (auto &Item : *Seq) {
+ auto *Node = dyn_cast<llvm::yaml::ScalarNode>(&Item);
+ if (!Node)
+ return llvm::None;
+ Result.extraFlags.push_back(Node->getValue(Storage));
+ }
+ }
+ }
+ return Result;
+}
+
llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params) {
TextEdit Result;
for (auto &NextKeyValue : *Params) {
@@ -265,6 +292,11 @@ DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
if (!Parsed)
return llvm::None;
Result.textDocument = std::move(*Parsed);
+ } else if (KeyValue == "metadata") {
+ auto Parsed = Metadata::parse(Value);
+ if (!Parsed)
+ return llvm::None;
+ Result.metadata = std::move(*Parsed);
} else {
return llvm::None;
}
diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h
index 2e0c33d6d90..8239d8b2774 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -118,6 +118,12 @@ struct Location {
static std::string unparse(const Location &P);
};
+struct Metadata {
+ std::vector<std::string> extraFlags;
+
+ static llvm::Optional<Metadata> parse(llvm::yaml::MappingNode *Params);
+};
+
struct TextEdit {
/// The range of the text document to be manipulated. To insert
/// text into a document create a range where start === end.
@@ -152,6 +158,9 @@ struct DidOpenTextDocumentParams {
/// The document that was opened.
TextDocumentItem textDocument;
+ /// Extension storing per-file metadata, such as compilation flags.
+ llvm::Optional<Metadata> metadata;
+
static llvm::Optional<DidOpenTextDocumentParams>
parse(llvm::yaml::MappingNode *Params);
};
diff --git a/clang-tools-extra/test/clangd/extra-flags.test b/clang-tools-extra/test/clangd/extra-flags.test
new file mode 100644
index 00000000000..4e5fcc9a4df
--- /dev/null
+++ b/clang-tools-extra/test/clangd/extra-flags.test
@@ -0,0 +1,22 @@
+# RUN: clangd -run-synchronously < %s | FileCheck %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+#
+Content-Length: 205
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///foo.c","languageId":"c","version":1,"text":"int main() { int i; return i; }"},"metadata":{"extraFlags":["-Wall"]}}}
+# CHECK: {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///foo.c","diagnostics":[{"range":{"start": {"line": 0, "character": 28}, "end": {"line": 0, "character": 28}},"severity":2,"message":"variable 'i' is uninitialized when used here"},{"range":{"start": {"line": 0, "character": 19}, "end": {"line": 0, "character": 19}},"severity":3,"message":"initialize the variable 'i' to silence this warning"}]}}
+#
+Content-Length: 175
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///foo.c","version":2},"contentChanges":[{"text":"int main() { int i; return i; }"}]}}
+# CHECK: {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///foo.c","diagnostics":[{"range":{"start": {"line": 0, "character": 28}, "end": {"line": 0, "character": 28}},"severity":2,"message":"variable 'i' is uninitialized when used here"},{"range":{"start": {"line": 0, "character": 19}, "end": {"line": 0, "character": 19}},"severity":3,"message":"initialize the variable 'i' to silence this warning"}]}}
+#
+Content-Length: 44
+
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
+
+
OpenPOWER on IntegriCloud