summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clangd/ClangdLSPServer.cpp2
-rw-r--r--clang-tools-extra/clangd/ClangdServer.cpp6
-rw-r--r--clang-tools-extra/clangd/ClangdUnit.cpp18
-rw-r--r--clang-tools-extra/clangd/CodeComplete.cpp47
-rw-r--r--clang-tools-extra/clangd/Compiler.cpp2
-rw-r--r--clang-tools-extra/clangd/Diagnostics.cpp2
-rw-r--r--clang-tools-extra/clangd/FileDistance.cpp18
-rw-r--r--clang-tools-extra/clangd/FindSymbols.cpp20
-rw-r--r--clang-tools-extra/clangd/GlobalCompilationDatabase.cpp2
-rw-r--r--clang-tools-extra/clangd/JSONRPCDispatcher.cpp43
-rw-r--r--clang-tools-extra/clangd/JSONRPCDispatcher.h9
-rw-r--r--clang-tools-extra/clangd/Logger.cpp13
-rw-r--r--clang-tools-extra/clangd/Logger.h65
-rw-r--r--clang-tools-extra/clangd/Protocol.cpp7
-rw-r--r--clang-tools-extra/clangd/ProtocolHandlers.cpp2
-rw-r--r--clang-tools-extra/clangd/SourceCode.cpp2
-rw-r--r--clang-tools-extra/clangd/TUScheduler.cpp10
-rw-r--r--clang-tools-extra/clangd/XRefs.cpp4
-rw-r--r--clang-tools-extra/clangd/index/SymbolCollector.cpp5
-rw-r--r--clang-tools-extra/clangd/tool/ClangdMain.cpp10
20 files changed, 177 insertions, 110 deletions
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 5ea1f793ba0..b8c2a79b644 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -160,7 +160,7 @@ void ClangdLSPServer::onDocumentDidChange(DidChangeTextDocumentParams &Params) {
DraftMgr.removeDraft(File);
Server.removeDocument(File);
CDB.invalidate(File);
- log(llvm::toString(Contents.takeError()));
+ elog("Failed to update {0}: {1}", File, Contents.takeError());
return;
}
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index bc6a9fb16b8..ed8cba5f1dd 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -118,12 +118,12 @@ void ClangdServer::setRootPath(PathRef RootPath) {
auto FS = FSProvider.getFileSystem();
auto Status = FS->status(RootPath);
if (!Status)
- log("Failed to get status for RootPath " + RootPath + ": " +
- Status.getError().message());
+ elog("Failed to get status for RootPath {0}: {1}", RootPath,
+ Status.getError().message());
else if (Status->isDirectory())
this->RootPath = RootPath;
else
- log("The provided RootPath " + RootPath + " is not a directory.");
+ elog("The provided RootPath {0} is not a directory.", RootPath);
}
void ClangdServer::addDocument(PathRef File, StringRef Contents,
diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp
index d91be1ee700..a5ab4839cca 100644
--- a/clang-tools-extra/clangd/ClangdUnit.cpp
+++ b/clang-tools-extra/clangd/ClangdUnit.cpp
@@ -147,7 +147,7 @@ ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI,
auto Action = llvm::make_unique<ClangdFrontendAction>();
const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
if (!Action->BeginSourceFile(*Clang, MainInput)) {
- log("BeginSourceFile() failed when building AST for " +
+ log("BeginSourceFile() failed when building AST for {0}",
MainInput.getFile());
return llvm::None;
}
@@ -159,7 +159,7 @@ ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI,
collectIncludeStructureCallback(Clang->getSourceManager(), &Includes));
if (!Action->Execute())
- log("Execute() failed when building AST for " + MainInput.getFile());
+ log("Execute() failed when building AST for {0}", MainInput.getFile());
// UnitDiagsConsumer is local, we can not store it in CompilerInstance that
// has a longer lifetime.
@@ -307,11 +307,11 @@ std::shared_ptr<const PreambleData> clangd::buildPreamble(
compileCommandsAreEqual(Inputs.CompileCommand, OldCompileCommand) &&
OldPreamble->Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
Inputs.FS.get())) {
- log("Reusing preamble for file " + Twine(FileName));
+ vlog("Reusing preamble for file {0}", Twine(FileName));
return OldPreamble;
}
- log("Preamble for file " + Twine(FileName) +
- " cannot be reused. Attempting to rebuild it.");
+ vlog("Preamble for file {0} cannot be reused. Attempting to rebuild it.",
+ FileName);
trace::Span Tracer("BuildPreamble");
SPAN_ATTACH(Tracer, "File", FileName);
@@ -343,13 +343,13 @@ std::shared_ptr<const PreambleData> clangd::buildPreamble(
CI.getFrontendOpts().SkipFunctionBodies = false;
if (BuiltPreamble) {
- log("Built preamble of size " + Twine(BuiltPreamble->getSize()) +
- " for file " + Twine(FileName));
+ vlog("Built preamble of size {0} for file {1}", BuiltPreamble->getSize(),
+ FileName);
return std::make_shared<PreambleData>(
std::move(*BuiltPreamble), PreambleDiagnostics.take(),
SerializedDeclsCollector.takeIncludes());
} else {
- log("Could not build a preamble for file " + Twine(FileName));
+ elog("Could not build a preamble for file {0}", FileName);
return nullptr;
}
}
@@ -379,7 +379,7 @@ SourceLocation clangd::getBeginningOfIdentifier(ParsedAST &Unit,
const SourceManager &SourceMgr = AST.getSourceManager();
auto Offset = positionToOffset(SourceMgr.getBufferData(FID), Pos);
if (!Offset) {
- log("getBeginningOfIdentifier: " + toString(Offset.takeError()));
+ log("getBeginningOfIdentifier: {0}", Offset.takeError());
return SourceLocation();
}
SourceLocation InputLoc = SourceMgr.getComposedLoc(FID, *Offset);
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index ded1113d117..7392529a00d 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -308,11 +308,10 @@ struct CodeCompletionBuilder {
if (Include->second)
Completion.HeaderInsertion = Includes.insert(Include->first);
} else
- log(llvm::formatv(
- "Failed to generate include insertion edits for adding header "
+ log("Failed to generate include insertion edits for adding header "
"(FileURI='{0}', IncludeHeader='{1}') into {2}",
C.IndexResult->CanonicalDeclaration.FileURI,
- C.IndexResult->Detail->IncludeHeader, FileName));
+ C.IndexResult->Detail->IncludeHeader, FileName);
}
}
@@ -593,11 +592,10 @@ struct CompletionRecorder : public CodeCompleteConsumer {
if (NumResults == 0 && !contextAllowsIndex(Context.getKind()))
return;
if (CCSema) {
- log(llvm::formatv(
- "Multiple code complete callbacks (parser backtracked?). "
+ log("Multiple code complete callbacks (parser backtracked?). "
"Dropping results from context {0}, keeping results from {1}.",
getCompletionKindString(Context.getKind()),
- getCompletionKindString(this->CCContext.getKind())));
+ getCompletionKindString(this->CCContext.getKind()));
return;
}
// Record the completion context.
@@ -798,7 +796,7 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
&DummyDiagsConsumer, false),
Input.VFS);
if (!CI) {
- log("Couldn't create CompilerInvocation");
+ elog("Couldn't create CompilerInvocation");
return false;
}
auto &FrontendOpts = CI->getFrontendOpts();
@@ -812,8 +810,7 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
FrontendOpts.CodeCompletionAt.FileName = Input.FileName;
auto Offset = positionToOffset(Input.Contents, Input.Pos);
if (!Offset) {
- log("Code completion position was invalid " +
- llvm::toString(Offset.takeError()));
+ elog("Code completion position was invalid {0}", Offset.takeError());
return false;
}
std::tie(FrontendOpts.CodeCompletionAt.Line,
@@ -836,7 +833,7 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
SyntaxOnlyAction Action;
if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
- log("BeginSourceFile() failed when running codeComplete for " +
+ log("BeginSourceFile() failed when running codeComplete for {0}",
Input.FileName);
return false;
}
@@ -844,7 +841,7 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
Clang->getPreprocessor().addPPCallbacks(
collectIncludeStructureCallback(Clang->getSourceManager(), Includes));
if (!Action.Execute()) {
- log("Execute() failed when running codeComplete for " + Input.FileName);
+ log("Execute() failed when running codeComplete for {0}", Input.FileName);
return false;
}
Action.EndSourceFile();
@@ -965,8 +962,8 @@ public:
format::DefaultFallbackStyle, SemaCCInput.Contents,
SemaCCInput.VFS.get());
if (!Style) {
- log("Failed to get FormatStyle for file" + SemaCCInput.FileName + ": " +
- llvm::toString(Style.takeError()) + ". Fallback is LLVM style.");
+ log("getStyle() failed for file {0}: {1}. Fallback is LLVM style.",
+ SemaCCInput.FileName, Style.takeError());
Style = format::getLLVMStyle();
}
// If preprocessor was run, inclusions from preprocessor callback should
@@ -1001,10 +998,9 @@ public:
Inserter.reset(); // Make sure this doesn't out-live Clang.
SPAN_ATTACH(Tracer, "sema_completion_kind",
getCompletionKindString(Recorder->CCContext.getKind()));
- log(llvm::formatv(
- "Code complete: sema context {0}, query scopes [{1}]",
+ log("Code complete: sema context {0}, query scopes [{1}]",
getCompletionKindString(Recorder->CCContext.getKind()),
- llvm::join(QueryScopes.begin(), QueryScopes.end(), ",")));
+ llvm::join(QueryScopes.begin(), QueryScopes.end(), ","));
});
Recorder = RecorderOwner.get();
@@ -1016,10 +1012,10 @@ public:
SPAN_ATTACH(Tracer, "merged_results", NBoth);
SPAN_ATTACH(Tracer, "returned_results", int64_t(Output.Completions.size()));
SPAN_ATTACH(Tracer, "incomplete", Output.HasMore);
- log(llvm::formatv("Code complete: {0} results from Sema, {1} from Index, "
- "{2} matched, {3} returned{4}.",
- NSema, NIndex, NBoth, Output.Completions.size(),
- Output.HasMore ? " (incomplete)" : ""));
+ log("Code complete: {0} results from Sema, {1} from Index, "
+ "{2} matched, {3} returned{4}.",
+ NSema, NIndex, NBoth, Output.Completions.size(),
+ Output.HasMore ? " (incomplete)" : "");
assert(!Opts.Limit || Output.Completions.size() <= Opts.Limit);
// We don't assert that isIncomplete means we hit a limit.
// Indexes may choose to impose their own limits even if we don't have one.
@@ -1068,9 +1064,8 @@ private:
Req.Scopes = QueryScopes;
// FIXME: we should send multiple weighted paths here.
Req.ProximityPaths.push_back(FileName);
- log(llvm::formatv("Code complete: fuzzyFind(\"{0}\", scopes=[{1}])",
- Req.Query,
- llvm::join(Req.Scopes.begin(), Req.Scopes.end(), ",")));
+ vlog("Code complete: fuzzyFind(\"{0}\", scopes=[{1}])", Req.Query,
+ llvm::join(Req.Scopes.begin(), Req.Scopes.end(), ","));
// Run the query against the index.
if (Opts.Index->fuzzyFind(
Req, [&](const Symbol &Sym) { ResultsBuilder.insert(Sym); }))
@@ -1178,9 +1173,9 @@ private:
? Scores.Total / Relevance.NameMatch
: Scores.Quality;
- LLVM_DEBUG(llvm::dbgs() << "CodeComplete: " << First.Name << " (" << Origin
- << ") = " << Scores.Total << "\n"
- << Quality << Relevance << "\n");
+ dlog("CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name,
+ llvm::to_string(Origin), Scores.Total, llvm::to_string(Quality),
+ llvm::to_string(Relevance));
NSema += bool(Origin & SymbolOrigin::AST);
NIndex += FromIndex;
diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp
index 80d5c5ac8cb..8fcc9a97cb9 100644
--- a/clang-tools-extra/clangd/Compiler.cpp
+++ b/clang-tools-extra/clangd/Compiler.cpp
@@ -31,7 +31,7 @@ void IgnoreDiagnostics::log(DiagnosticsEngine::Level DiagLevel,
OS << ":";
}
- clangd::log(llvm::formatv("Ignored diagnostic. {0}{1}", Location, Message));
+ clangd::log("Ignored diagnostic. {0}{1}", Location, Message);
}
void IgnoreDiagnostics::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp
index a52891bb628..73ac475efef 100644
--- a/clang-tools-extra/clangd/Diagnostics.cpp
+++ b/clang-tools-extra/clangd/Diagnostics.cpp
@@ -375,7 +375,7 @@ void StoreDiags::flushLastDiag() {
if (mentionsMainFile(*LastDiag))
Output.push_back(std::move(*LastDiag));
else
- log(Twine("Dropped diagnostic outside main file:") + LastDiag->File + ":" +
+ log("Dropped diagnostic outside main file: {0}: {1}", LastDiag->File,
LastDiag->Message);
LastDiag.reset();
}
diff --git a/clang-tools-extra/clangd/FileDistance.cpp b/clang-tools-extra/clangd/FileDistance.cpp
index 5a3650af27b..a0ce25b48fa 100644
--- a/clang-tools-extra/clangd/FileDistance.cpp
+++ b/clang-tools-extra/clangd/FileDistance.cpp
@@ -35,7 +35,6 @@
#include "Logger.h"
#include "llvm/ADT/STLExtras.h"
#include <queue>
-#define DEBUG_TYPE "FileDistance"
namespace clang {
namespace clangd {
@@ -64,8 +63,8 @@ FileDistance::FileDistance(StringMap<SourceParams> Sources,
// Keep track of down edges, in case we can use them to improve on this.
for (const auto &S : Sources) {
auto Canonical = canonicalize(S.getKey());
- LLVM_DEBUG(dbgs() << "Source " << Canonical << " = " << S.second.Cost
- << ", MaxUp=" << S.second.MaxUpTraversals << "\n");
+ dlog("Source {0} = {1}, MaxUp = {2}", Canonical, S.second.Cost,
+ S.second.MaxUpTraversals);
// Walk up to ancestors of this source, assigning cost.
StringRef Rest = Canonical;
llvm::hash_code Hash = hash_value(Rest);
@@ -134,7 +133,7 @@ unsigned FileDistance::distance(StringRef Path) {
Cost += Opts.DownCost;
Cache.try_emplace(Hash, Cost);
}
- LLVM_DEBUG(dbgs() << "distance(" << Path << ") = " << Cost << "\n");
+ dlog("distance({0} = {1})", Path, Cost);
return Cost;
}
@@ -143,12 +142,10 @@ unsigned URIDistance::distance(llvm::StringRef URI) {
if (!R.second)
return R.first->getSecond();
if (auto U = clangd::URI::parse(URI)) {
- LLVM_DEBUG(dbgs() << "distance(" << URI << ") = distance(" << U->body()
- << ")\n");
+ dlog("distance({0} = {1})", URI, U->body());
R.first->second = forScheme(U->scheme()).distance(U->body());
} else {
- log("URIDistance::distance() of unparseable " + URI + ": " +
- llvm::toString(U.takeError()));
+ log("URIDistance::distance() of unparseable {0}: {1}", URI, U.takeError());
}
return R.first->second;
}
@@ -163,9 +160,8 @@ FileDistance &URIDistance::forScheme(llvm::StringRef Scheme) {
else
consumeError(U.takeError());
}
- LLVM_DEBUG(dbgs() << "FileDistance for scheme " << Scheme << ": "
- << SchemeSources.size() << "/" << Sources.size()
- << " sources\n");
+ dlog("FileDistance for scheme {0}: {1}/{2} sources", Scheme,
+ SchemeSources.size(), Sources.size());
Delegate.reset(new FileDistance(std::move(SchemeSources), Opts));
}
return *Delegate;
diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp
index d4f9c037daf..c1ee678977d 100644
--- a/clang-tools-extra/clangd/FindSymbols.cpp
+++ b/clang-tools-extra/clangd/FindSymbols.cpp
@@ -125,16 +125,15 @@ getWorkspaceSymbols(StringRef Query, int Limit, const SymbolIndex *const Index,
auto &CD = Sym.Definition ? Sym.Definition : Sym.CanonicalDeclaration;
auto Uri = URI::parse(CD.FileURI);
if (!Uri) {
- log(llvm::formatv(
- "Workspace symbol: Could not parse URI '{0}' for symbol '{1}'.",
- CD.FileURI, Sym.Name));
+ log("Workspace symbol: Could not parse URI '{0}' for symbol '{1}'.",
+ CD.FileURI, Sym.Name);
return;
}
auto Path = URI::resolve(*Uri, HintPath);
if (!Path) {
- log(llvm::formatv("Workspace symbol: Could not resolve path for URI "
- "'{0}' for symbol '{1}'.",
- (*Uri).toString(), Sym.Name.str()));
+ log("Workspace symbol: Could not resolve path for URI '{0}' for symbol "
+ "'{1}'.",
+ Uri->toString(), Sym.Name);
return;
}
Location L;
@@ -158,16 +157,15 @@ getWorkspaceSymbols(StringRef Query, int Limit, const SymbolIndex *const Index,
if (auto NameMatch = Filter.match(Sym.Name))
Relevance.NameMatch = *NameMatch;
else {
- log(llvm::formatv("Workspace symbol: {0} didn't match query {1}",
- Sym.Name, Filter.pattern()));
+ log("Workspace symbol: {0} didn't match query {1}", Sym.Name,
+ Filter.pattern());
return;
}
Relevance.merge(Sym);
auto Score =
evaluateSymbolAndRelevance(Quality.evaluate(), Relevance.evaluate());
- LLVM_DEBUG(llvm::dbgs() << "FindSymbols: " << Sym.Scope << Sym.Name << " = "
- << Score << "\n"
- << Quality << Relevance << "\n");
+ dlog("FindSymbols: {0}{1} = {2}\n{3}{4}\n", Sym.Scope, Sym.Name, Score,
+ Quality, Relevance);
Top.push({Score, std::move(Info)});
});
diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
index a8ac58d3d4d..be03e4c2463 100644
--- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -47,7 +47,7 @@ DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const {
return std::move(Candidates.front());
}
} else {
- log("Failed to find compilation database for " + Twine(File));
+ log("Failed to find compilation database for {0}", File);
}
return llvm::None;
}
diff --git a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
index f81af3d1dda..d273577e28f 100644
--- a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
+++ b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Errno.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/SourceMgr.h"
#include <istream>
@@ -68,14 +69,18 @@ void JSONOutput::writeMessage(const json::Value &Message) {
Outs << "Content-Length: " << S.size() << "\r\n\r\n" << S;
Outs.flush();
}
- log(llvm::Twine("--> ") + S + "\n");
+ vlog("--> {0}\n", S);
}
-void JSONOutput::log(const Twine &Message) {
+void JSONOutput::log(Logger::Level Level,
+ const llvm::formatv_object_base &Message) {
+ if (Level < MinLevel)
+ return;
llvm::sys::TimePoint<> Timestamp = std::chrono::system_clock::now();
trace::log(Message);
std::lock_guard<std::mutex> Guard(StreamMutex);
- Logs << llvm::formatv("[{0:%H:%M:%S.%L}] {1}\n", Timestamp, Message);
+ Logs << llvm::formatv("{0}[{1:%H:%M:%S.%L}] {2}\n", indicator(Level),
+ Timestamp, Message);
Logs.flush();
}
@@ -90,7 +95,7 @@ void JSONOutput::mirrorInput(const Twine &Message) {
void clangd::reply(json::Value &&Result) {
auto ID = Context::current().get(RequestID);
if (!ID) {
- log("Attempted to reply to a notification!");
+ elog("Attempted to reply to a notification!");
return;
}
RequestSpan::attach([&](json::Object &Args) { Args["Reply"] = Result; });
@@ -104,7 +109,7 @@ void clangd::reply(json::Value &&Result) {
}
void clangd::replyError(ErrorCode code, const llvm::StringRef &Message) {
- log("Error " + Twine(static_cast<int>(code)) + ": " + Message);
+ elog("Error {0}: {1}", static_cast<int>(code), Message);
RequestSpan::attach([&](json::Object &Args) {
Args["Error"] = json::Object{{"code", static_cast<int>(code)},
{"message", Message.str()}};
@@ -230,9 +235,9 @@ static llvm::Optional<std::string> readStandardMessage(std::FILE *In,
// Content-Length is a mandatory header, and the only one we handle.
if (LineRef.consume_front("Content-Length: ")) {
if (ContentLength != 0) {
- log("Warning: Duplicate Content-Length header received. "
- "The previous value for this message (" +
- llvm::Twine(ContentLength) + ") was ignored.");
+ elog("Warning: Duplicate Content-Length header received. "
+ "The previous value for this message ({0}) was ignored.",
+ ContentLength);
}
llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
continue;
@@ -248,8 +253,9 @@ static llvm::Optional<std::string> readStandardMessage(std::FILE *In,
// The fuzzer likes crashing us by sending "Content-Length: 9999999999999999"
if (ContentLength > 1 << 30) { // 1024M
- log("Refusing to read message with long Content-Length: " +
- Twine(ContentLength) + ". Expect protocol errors.");
+ elog("Refusing to read message with long Content-Length: {0}. "
+ "Expect protocol errors",
+ ContentLength);
return llvm::None;
}
if (ContentLength == 0) {
@@ -264,8 +270,8 @@ static llvm::Optional<std::string> readStandardMessage(std::FILE *In,
ContentLength - Pos, In);
Out.mirrorInput(StringRef(&JSON[Pos], Read));
if (Read == 0) {
- log("Input was aborted. Read only " + llvm::Twine(Pos) +
- " bytes of expected " + llvm::Twine(ContentLength) + ".");
+ elog("Input was aborted. Read only {0} bytes of expected {1}.", Pos,
+ ContentLength);
return llvm::None;
}
clearerr(In); // If we're done, the error was transient. If we're not done,
@@ -297,7 +303,7 @@ static llvm::Optional<std::string> readDelimitedMessage(std::FILE *In,
}
if (ferror(In)) {
- log("Input error while reading message!");
+ elog("Input error while reading message!");
return llvm::None;
} else { // Including EOF
Out.mirrorInput(
@@ -321,21 +327,20 @@ void clangd::runLanguageServerLoop(std::FILE *In, JSONOutput &Out,
(InputStyle == Delimited) ? readDelimitedMessage : readStandardMessage;
while (!IsDone && !feof(In)) {
if (ferror(In)) {
- log("IO error: " + llvm::sys::StrError());
+ elog("IO error: {0}", llvm::sys::StrError());
return;
}
if (auto JSON = ReadMessage(In, Out)) {
if (auto Doc = json::parse(*JSON)) {
// Log the formatted message.
- log(llvm::formatv(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc));
+ vlog(Out.Pretty ? "<-- {0:2}\n" : "<-- {0}\n", *Doc);
// Finally, execute the action for this JSON message.
if (!Dispatcher.call(*Doc, Out))
- log("JSON dispatch failed!");
+ elog("JSON dispatch failed!");
} else {
// Parse error. Log the raw message.
- log(llvm::formatv("<-- {0}\n" , *JSON));
- log(llvm::Twine("JSON parse error: ") +
- llvm::toString(Doc.takeError()));
+ vlog("<-- {0}\n", *JSON);
+ elog("JSON parse error: {0}", llvm::toString(Doc.takeError()));
}
}
}
diff --git a/clang-tools-extra/clangd/JSONRPCDispatcher.h b/clang-tools-extra/clangd/JSONRPCDispatcher.h
index 3c0387ca2ef..a3912126d8f 100644
--- a/clang-tools-extra/clangd/JSONRPCDispatcher.h
+++ b/clang-tools-extra/clangd/JSONRPCDispatcher.h
@@ -30,14 +30,16 @@ class JSONOutput : public Logger {
// JSONOutput now that we pass Context everywhere.
public:
JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs,
- llvm::raw_ostream *InputMirror = nullptr, bool Pretty = false)
- : Pretty(Pretty), Outs(Outs), Logs(Logs), InputMirror(InputMirror) {}
+ Logger::Level MinLevel, llvm::raw_ostream *InputMirror = nullptr,
+ bool Pretty = false)
+ : Pretty(Pretty), MinLevel(MinLevel), Outs(Outs), Logs(Logs),
+ InputMirror(InputMirror) {}
/// Emit a JSONRPC message.
void writeMessage(const llvm::json::Value &Result);
/// Write a line to the logging stream.
- void log(const Twine &Message) override;
+ void log(Level, const llvm::formatv_object_base &Message) override;
/// Mirror \p Message into InputMirror stream. Does nothing if InputMirror is
/// null.
@@ -48,6 +50,7 @@ public:
const bool Pretty;
private:
+ Logger::Level MinLevel;
llvm::raw_ostream &Outs;
llvm::raw_ostream &Logs;
llvm::raw_ostream *InputMirror;
diff --git a/clang-tools-extra/clangd/Logger.cpp b/clang-tools-extra/clangd/Logger.cpp
index 08253844725..5ce3351f13e 100644
--- a/clang-tools-extra/clangd/Logger.cpp
+++ b/clang-tools-extra/clangd/Logger.cpp
@@ -25,9 +25,10 @@ LoggingSession::LoggingSession(clangd::Logger &Instance) {
LoggingSession::~LoggingSession() { L = nullptr; }
-void log(const llvm::Twine &Message) {
+void detail::log(Logger::Level Level,
+ const llvm::formatv_object_base &Message) {
if (L)
- L->log(Message);
+ L->log(Level, Message);
else {
static std::mutex Mu;
std::lock_guard<std::mutex> Guard(Mu);
@@ -35,5 +36,13 @@ void log(const llvm::Twine &Message) {
}
}
+const char *detail::debugType(const char *Filename) {
+ if (const char *Slash = strrchr(Filename, '/'))
+ return Slash + 1;
+ if (const char *Backslash = strrchr(Filename, '\\'))
+ return Backslash + 1;
+ return Filename;
+}
+
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/Logger.h b/clang-tools-extra/clangd/Logger.h
index 7811111a2f6..30dd6cc2ad0 100644
--- a/clang-tools-extra/clangd/Logger.h
+++ b/clang-tools-extra/clangd/Logger.h
@@ -11,24 +11,77 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_LOGGER_H
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
namespace clang {
namespace clangd {
-/// Main logging function.
-/// Logs messages to a global logger, which can be set up by LoggingSesssion.
-/// If no logger is registered, writes to llvm::errs().
-void log(const llvm::Twine &Message);
-
/// Interface to allow custom logging in clangd.
class Logger {
public:
virtual ~Logger() = default;
+ enum Level { Debug, Verbose, Info, Error };
+ static char indicator(Level L) { return "DVIE"[L]; }
+
/// Implementations of this method must be thread-safe.
- virtual void log(const llvm::Twine &Message) = 0;
+ virtual void log(Level, const llvm::formatv_object_base &Message) = 0;
};
+namespace detail {
+const char *debugType(const char *Filename);
+void log(Logger::Level, const llvm::formatv_object_base &);
+
+// We often want to consume llvm::Errors by value when passing them to log().
+// This is tricky because the logging infrastructure must mark them as handled.
+// When forwarding argument to formatv, we wrap Errors-by-value in this type
+// whose destructor handles the cleanup.
+// FIXME: simplify after D49170 lands.
+struct WrappedError {
+ llvm::Error E;
+ WrappedError(WrappedError &&) = default;
+ ~WrappedError() { consumeError(std::move(E)); }
+};
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const WrappedError &Err) {
+ return OS << Err.E;
+}
+template <typename T> T &&wrap(T &&V) { return std::forward<T>(V); }
+inline WrappedError wrap(llvm::Error &&V) { return WrappedError{std::move(V)}; }
+template <typename... Ts>
+void log(Logger::Level L, const char *Fmt, Ts &&... Vals) {
+ detail::log(L, llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...));
+}
+} // namespace detail
+
+// Clangd logging functions write to a global logger set by LoggingSession.
+// If no logger is registered, writes to llvm::errs().
+// All accept llvm::formatv()-style arguments, e.g. log("Text={0}", Text).
+
+// elog() is used for "loud" errors and warnings.
+// This level is often visible to users.
+template <typename... Ts> void elog(const char *Fmt, Ts &&... Vals) {
+ detail::log(Logger::Error, Fmt, std::forward<Ts>(Vals)...);
+}
+// log() is used for information important to understanding a clangd session.
+// e.g. the names of LSP messages sent are logged at this level.
+// This level could be enabled in production builds to allow later inspection.
+template <typename... Ts> void log(const char *Fmt, Ts &&... Vals) {
+ detail::log(Logger::Info, Fmt, std::forward<Ts>(Vals)...);
+}
+// vlog() is used for details often needed for debugging clangd sessions.
+// This level would typically be enabled for clangd developers.
+template <typename... Ts> void vlog(const char *Fmt, Ts &&... Vals) {
+ detail::log(Logger::Verbose, Fmt, std::forward<Ts>(Vals)...);
+}
+// dlog only logs if --debug was passed, or --debug_only=Basename.
+// This level would be enabled in a targeted way when debugging.
+#define dlog(...) \
+ DEBUG_WITH_TYPE(::clang::clangd::detail::debugType(__FILE__), \
+ ::clang::clangd::detail::log(Logger::Debug, __VA_ARGS__))
+
/// Only one LoggingSession can be active at a time.
class LoggingSession {
public:
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index a35e6ba8d27..8d99e18d68b 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -34,16 +34,17 @@ bool fromJSON(const json::Value &E, URIForFile &R) {
if (auto S = E.getAsString()) {
auto U = URI::parse(*S);
if (!U) {
- log("Failed to parse URI " + *S + ": " + llvm::toString(U.takeError()));
+ elog("Failed to parse URI {0}: {1}", *S, U.takeError());
return false;
}
if (U->scheme() != "file" && U->scheme() != "test") {
- log("Clangd only supports 'file' URI scheme for workspace files: " + *S);
+ elog("Clangd only supports 'file' URI scheme for workspace files: {0}",
+ *S);
return false;
}
auto Path = URI::resolve(*U);
if (!Path) {
- log(llvm::toString(Path.takeError()));
+ log("{0}", Path.takeError());
return false;
}
R = URIForFile(*Path);
diff --git a/clang-tools-extra/clangd/ProtocolHandlers.cpp b/clang-tools-extra/clangd/ProtocolHandlers.cpp
index 400f3f5d0f3..deb5b9d096d 100644
--- a/clang-tools-extra/clangd/ProtocolHandlers.cpp
+++ b/clang-tools-extra/clangd/ProtocolHandlers.cpp
@@ -33,7 +33,7 @@ struct HandlerRegisterer {
if (fromJSON(RawParams, P)) {
(Callbacks->*Handler)(P);
} else {
- log("Failed to decode " + Method + " request.");
+ elog("Failed to decode {0} request.", Method);
}
});
}
diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp
index b7402893eb6..d302518b061 100644
--- a/clang-tools-extra/clangd/SourceCode.cpp
+++ b/clang-tools-extra/clangd/SourceCode.cpp
@@ -192,7 +192,7 @@ getAbsoluteFilePath(const FileEntry *F, const SourceManager &SourceMgr) {
FilePath = F->getName();
if (!llvm::sys::path::is_absolute(FilePath)) {
if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) {
- log("Could not turn relative path to absolute: " + FilePath);
+ log("Could not turn relative path to absolute: {0}", FilePath);
return llvm::None;
}
}
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp
index ea543e5dcca..86617631a92 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -329,14 +329,14 @@ void ASTWorker::update(
// Remove the old AST if it's still in cache.
IdleASTs.take(this);
- log("Updating file " + FileName + " with command [" +
- Inputs.CompileCommand.Directory + "] " +
+ log("Updating file {0} with command [{1}] {2}", FileName,
+ Inputs.CompileCommand.Directory,
llvm::join(Inputs.CompileCommand.CommandLine, " "));
// Rebuild the preamble and the AST.
std::unique_ptr<CompilerInvocation> Invocation =
buildCompilerInvocation(Inputs);
if (!Invocation) {
- log("Could not build CompilerInvocation for file " + FileName);
+ elog("Could not build CompilerInvocation for file {0}", FileName);
// Make sure anyone waiting for the preamble gets notified it could not
// be built.
PreambleWasBuilt.notify();
@@ -628,8 +628,8 @@ void TUScheduler::update(
void TUScheduler::remove(PathRef File) {
bool Removed = Files.erase(File);
if (!Removed)
- log("Trying to remove file from TUScheduler that is not tracked. File:" +
- File);
+ elog("Trying to remove file from TUScheduler that is not tracked: {0}",
+ File);
}
void TUScheduler::runWithAST(
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index 8b65883eecb..93882062b0f 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -46,12 +46,12 @@ llvm::Optional<Location> ToLSPLocation(const SymbolLocation &Loc,
return llvm::None;
auto Uri = URI::parse(Loc.FileURI);
if (!Uri) {
- log("Could not parse URI: " + Loc.FileURI);
+ log("Could not parse URI: {0}", Loc.FileURI);
return llvm::None;
}
auto Path = URI::resolve(*Uri, HintPath);
if (!Path) {
- log("Could not resolve URI: " + Loc.FileURI);
+ log("Could not resolve URI: {0}", Loc.FileURI);
return llvm::None;
}
Location LSPLoc;
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index 568dff9594a..5c80f38454c 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -52,7 +52,7 @@ llvm::Optional<std::string> toURI(const SourceManager &SM, StringRef Path,
if (std::error_code EC =
SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
AbsolutePath))
- log("Warning: could not make absolute file: " + EC.message());
+ log("Warning: could not make absolute file: {0}", EC.message());
if (llvm::sys::path::is_absolute(AbsolutePath)) {
// Handle the symbolic link path case where the current working directory
// (getCurrentWorkingDirectory) is a symlink./ We always want to the real
@@ -86,8 +86,7 @@ llvm::Optional<std::string> toURI(const SourceManager &SM, StringRef Path,
return U->toString();
ErrMsg += llvm::toString(U.takeError()) + "\n";
}
- log(llvm::Twine("Failed to create an URI for file ") + AbsolutePath + ": " +
- ErrMsg);
+ log("Failed to create an URI for file {0}: {1}", AbsolutePath, ErrMsg);
return llvm::None;
}
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index dca633f41db..f04a975344c 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -98,6 +98,14 @@ static llvm::cl::opt<bool>
PrettyPrint("pretty", llvm::cl::desc("Pretty-print JSON output"),
llvm::cl::init(false));
+static llvm::cl::opt<Logger::Level> LogLevel(
+ "log", llvm::cl::desc("Verbosity of log messages written to stderr"),
+ llvm::cl::values(clEnumValN(Logger::Error, "error", "Error messages only"),
+ clEnumValN(Logger::Info, "info",
+ "High level execution tracing"),
+ clEnumValN(Logger::Debug, "verbose", "Low level details")),
+ llvm::cl::init(Logger::Info));
+
static llvm::cl::opt<bool> Test(
"lit-test",
llvm::cl::desc(
@@ -223,7 +231,7 @@ int main(int argc, char *argv[]) {
if (Tracer)
TracingSession.emplace(*Tracer);
- JSONOutput Out(llvm::outs(), llvm::errs(),
+ JSONOutput Out(llvm::outs(), llvm::errs(), LogLevel,
InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,
PrettyPrint);