[clang-tools-extra] 30667c9 - [clangd] Add error() function for creating formatv-style llvm::Errors. NFC
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 14 01:53:05 PDT 2020
Author: Sam McCall
Date: 2020-09-14T10:43:42+02:00
New Revision: 30667c967d3f420d3f53fb1c9c2465550a1112df
URL: https://github.com/llvm/llvm-project/commit/30667c967d3f420d3f53fb1c9c2465550a1112df
DIFF: https://github.com/llvm/llvm-project/commit/30667c967d3f420d3f53fb1c9c2465550a1112df.diff
LOG: [clangd] Add error() function for creating formatv-style llvm::Errors. NFC
Summary:
This is considerably terser than the makeStringError and friends, and
avoids verbosity cliffs that discourage adding log information.
It follows the syntax used in log/elog/vlog/dlog that have been successful.
The main caveats are:
- it's strictly out-of-place in logger.h, though kind of fits thematically and
in implementation
- it claims the "error" identifier, which seems a bit too opinionated
to put higher up in llvm
I've updated some users of StringError mostly at random - there are lots
more mechanical changes but I'd like to get this reviewed before making
them all.
Reviewers: kbobyrev, hokein
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83419
Added:
clang-tools-extra/clangd/unittests/LoggerTests.cpp
Modified:
clang-tools-extra/clangd/ClangdLSPServer.cpp
clang-tools-extra/clangd/ClangdServer.cpp
clang-tools-extra/clangd/CodeComplete.cpp
clang-tools-extra/clangd/DraftStore.cpp
clang-tools-extra/clangd/JSONTransport.cpp
clang-tools-extra/clangd/PathMapping.cpp
clang-tools-extra/clangd/RIFF.cpp
clang-tools-extra/clangd/TUScheduler.cpp
clang-tools-extra/clangd/index/Serialization.cpp
clang-tools-extra/clangd/support/Logger.cpp
clang-tools-extra/clangd/support/Logger.h
clang-tools-extra/clangd/unittests/CMakeLists.txt
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 6ebb71c3b4d1..4cc1feabb15f 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -147,13 +147,9 @@ llvm::Error validateEdits(const DraftStore &DraftMgr, const FileEdits &FE) {
if (!InvalidFileCount)
return llvm::Error::success();
if (InvalidFileCount == 1)
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "File must be saved first: " +
- LastInvalidFile);
- return llvm::createStringError(
- llvm::inconvertibleErrorCode(),
- "Files must be saved first: " + LastInvalidFile + " (and " +
- llvm::to_string(InvalidFileCount - 1) + " others)");
+ return error("File must be saved first: {0}", LastInvalidFile);
+ return error("Files must be saved first: {0} (and {1} others)",
+ LastInvalidFile, InvalidFileCount - 1);
}
} // namespace
@@ -284,10 +280,9 @@ class ClangdLSPServer::MessageHandler : public Transport::MessageHandler {
}
}
if (OldestCB)
- OldestCB->second(llvm::createStringError(
- llvm::inconvertibleErrorCode(),
- llvm::formatv("failed to receive a client reply for request ({0})",
- OldestCB->first)));
+ OldestCB->second(
+ error("failed to receive a client reply for request ({0})",
+ OldestCB->first));
return ID;
}
@@ -661,8 +656,7 @@ void ClangdLSPServer::onSync(const NoParams &Params,
if (Server->blockUntilIdleForTest(/*TimeoutSeconds=*/60))
Reply(nullptr);
else
- Reply(llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Not idle after a minute"));
+ Reply(error("Not idle after a minute"));
}
void ClangdLSPServer::onDocumentDidOpen(
@@ -729,9 +723,7 @@ void ClangdLSPServer::onCommand(const ExecuteCommandParams &Params,
std::string Reason = Response->failureReason
? *Response->failureReason
: "unknown reason";
- return Reply(llvm::createStringError(
- llvm::inconvertibleErrorCode(),
- ("edits were not applied: " + Reason).c_str()));
+ return Reply(error("edits were not applied: {0}", Reason));
}
return Reply(SuccessMessage);
});
@@ -752,9 +744,7 @@ void ClangdLSPServer::onCommand(const ExecuteCommandParams &Params,
Params.tweakArgs) {
auto Code = DraftMgr.getDraft(Params.tweakArgs->file.file());
if (!Code)
- return Reply(llvm::createStringError(
- llvm::inconvertibleErrorCode(),
- "trying to apply a code action for a non-added file"));
+ return Reply(error("trying to apply a code action for a non-added file"));
auto Action = [this, ApplyEdit, Reply = std::move(Reply),
File = Params.tweakArgs->file, Code = std::move(*Code)](
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index d204e87c143b..a571ff56ce4c 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -342,8 +342,7 @@ void ClangdServer::signatureHelp(PathRef File, Position Pos,
const auto *PreambleData = IP->Preamble;
if (!PreambleData)
- return CB(llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Failed to parse includes"));
+ return CB(error("Failed to parse includes"));
ParseInputs ParseInput{IP->Command, &TFS, IP->Contents.str()};
ParseInput.Index = Index;
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 92ebc4c39f64..4d5b2975c9ae 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -333,8 +333,7 @@ struct CodeCompletionBuilder {
return ResolvedInserted.takeError();
auto Spelled = Includes.calculateIncludePath(*ResolvedInserted, FileName);
if (!Spelled)
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Header not on include path");
+ return error("Header not on include path");
return std::make_pair(
std::move(*Spelled),
Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted));
diff --git a/clang-tools-extra/clangd/DraftStore.cpp b/clang-tools-extra/clangd/DraftStore.cpp
index bef48ddfa37d..1299efbfba9f 100644
--- a/clang-tools-extra/clangd/DraftStore.cpp
+++ b/clang-tools-extra/clangd/DraftStore.cpp
@@ -64,9 +64,9 @@ llvm::Expected<DraftStore::Draft> DraftStore::updateDraft(
auto EntryIt = Drafts.find(File);
if (EntryIt == Drafts.end()) {
- return llvm::make_error<llvm::StringError>(
- "Trying to do incremental update on non-added document: " + File,
- llvm::errc::invalid_argument);
+ return error(llvm::errc::invalid_argument,
+ "Trying to do incremental update on non-added document: {0}",
+ File);
}
Draft &D = EntryIt->second;
std::string Contents = EntryIt->second.Contents;
@@ -89,11 +89,9 @@ llvm::Expected<DraftStore::Draft> DraftStore::updateDraft(
return EndIndex.takeError();
if (*EndIndex < *StartIndex)
- return llvm::make_error<llvm::StringError>(
- llvm::formatv(
- "Range's end position ({0}) is before start position ({1})", End,
- Start),
- llvm::errc::invalid_argument);
+ return error(llvm::errc::invalid_argument,
+ "Range's end position ({0}) is before start position ({1})",
+ End, Start);
// Since the range length between two LSP positions is dependent on the
// contents of the buffer we compute the range length between the start and
@@ -106,11 +104,10 @@ llvm::Expected<DraftStore::Draft> DraftStore::updateDraft(
lspLength(Contents.substr(*StartIndex, *EndIndex - *StartIndex));
if (Change.rangeLength && ComputedRangeLength != *Change.rangeLength)
- return llvm::make_error<llvm::StringError>(
- llvm::formatv("Change's rangeLength ({0}) doesn't match the "
- "computed range length ({1}).",
- *Change.rangeLength, ComputedRangeLength),
- llvm::errc::invalid_argument);
+ return error(llvm::errc::invalid_argument,
+ "Change's rangeLength ({0}) doesn't match the "
+ "computed range length ({1}).",
+ *Change.rangeLength, ComputedRangeLength);
std::string NewContents;
NewContents.reserve(*StartIndex + Change.text.length() +
diff --git a/clang-tools-extra/clangd/JSONTransport.cpp b/clang-tools-extra/clangd/JSONTransport.cpp
index fa86baf6c581..c591da0db47d 100644
--- a/clang-tools-extra/clangd/JSONTransport.cpp
+++ b/clang-tools-extra/clangd/JSONTransport.cpp
@@ -51,12 +51,10 @@ llvm::json::Object encodeError(llvm::Error E) {
}
llvm::Error decodeError(const llvm::json::Object &O) {
- std::string Msg =
- std::string(O.getString("message").getValueOr("Unspecified error"));
+ llvm::StringRef Msg = O.getString("message").getValueOr("Unspecified error");
if (auto Code = O.getInteger("code"))
- return llvm::make_error<LSPError>(std::move(Msg), ErrorCode(*Code));
- return llvm::make_error<llvm::StringError>(std::move(Msg),
- llvm::inconvertibleErrorCode());
+ return llvm::make_error<LSPError>(Msg.str(), ErrorCode(*Code));
+ return error(Msg.str());
}
class JSONTransport : public Transport {
diff --git a/clang-tools-extra/clangd/PathMapping.cpp b/clang-tools-extra/clangd/PathMapping.cpp
index eb568b917966..0cd9d22b998c 100644
--- a/clang-tools-extra/clangd/PathMapping.cpp
+++ b/clang-tools-extra/clangd/PathMapping.cpp
@@ -8,6 +8,7 @@
#include "PathMapping.h"
#include "Transport.h"
#include "URI.h"
+#include "support/Logger.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Errno.h"
@@ -156,8 +157,7 @@ llvm::Expected<std::string> parsePath(llvm::StringRef Path) {
Converted = "/" + Converted;
return Converted;
}
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Path not absolute: " + Path);
+ return error("Path not absolute: {0}", Path);
}
} // namespace
@@ -174,9 +174,7 @@ parsePathMappings(llvm::StringRef RawPathMappings) {
std::tie(PathPair, Rest) = Rest.split(",");
std::tie(ClientPath, ServerPath) = PathPair.split("=");
if (ClientPath.empty() || ServerPath.empty())
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Not a valid path mapping pair: " +
- PathPair);
+ return error("Not a valid path mapping pair: {0}", PathPair);
llvm::Expected<std::string> ParsedClientPath = parsePath(ClientPath);
if (!ParsedClientPath)
return ParsedClientPath.takeError();
diff --git a/clang-tools-extra/clangd/RIFF.cpp b/clang-tools-extra/clangd/RIFF.cpp
index f59200bd5856..8423580f9b46 100644
--- a/clang-tools-extra/clangd/RIFF.cpp
+++ b/clang-tools-extra/clangd/RIFF.cpp
@@ -7,35 +7,28 @@
//===----------------------------------------------------------------------===//
#include "RIFF.h"
+#include "support/Logger.h"
#include "llvm/Support/Endian.h"
-#include "llvm/Support/Error.h"
namespace clang {
namespace clangd {
namespace riff {
-static llvm::Error makeError(const llvm::Twine &Msg) {
- return llvm::make_error<llvm::StringError>(Msg,
- llvm::inconvertibleErrorCode());
-}
-
llvm::Expected<Chunk> readChunk(llvm::StringRef &Stream) {
if (Stream.size() < 8)
- return makeError("incomplete chunk header: " + llvm::Twine(Stream.size()) +
- " bytes available");
+ return error("incomplete chunk header: {0} bytes available", Stream.size());
Chunk C;
std::copy(Stream.begin(), Stream.begin() + 4, C.ID.begin());
Stream = Stream.drop_front(4);
uint32_t Len = llvm::support::endian::read32le(Stream.take_front(4).begin());
Stream = Stream.drop_front(4);
if (Stream.size() < Len)
- return makeError("truncated chunk: want " + llvm::Twine(Len) + ", got " +
- llvm::Twine(Stream.size()));
+ return error("truncated chunk: want {0}, got {1}", Len, Stream.size());
C.Data = Stream.take_front(Len);
Stream = Stream.drop_front(Len);
if ((Len % 2) && !Stream.empty()) { // Skip padding byte.
if (Stream.front())
- return makeError("nonzero padding byte");
+ return error("nonzero padding byte");
Stream = Stream.drop_front();
}
return std::move(C);
@@ -57,9 +50,9 @@ llvm::Expected<File> readFile(llvm::StringRef Stream) {
if (!RIFF)
return RIFF.takeError();
if (RIFF->ID != fourCC("RIFF"))
- return makeError("not a RIFF container: root is " + fourCCStr(RIFF->ID));
+ return error("not a RIFF container: root is {0}", fourCCStr(RIFF->ID));
if (RIFF->Data.size() < 4)
- return makeError("RIFF chunk too short");
+ return error("RIFF chunk too short");
File F;
std::copy(RIFF->Data.begin(), RIFF->Data.begin() + 4, F.Type.begin());
for (llvm::StringRef Body = RIFF->Data.drop_front(4); !Body.empty();)
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp
index ed367005177b..c408c8c0731d 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -717,8 +717,7 @@ void ASTWorker::runWithAST(
[&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
// Run the user-provided action.
if (!*AST)
- return Action(llvm::make_error<llvm::StringError>(
- "invalid AST", llvm::errc::invalid_argument));
+ return Action(error(llvm::errc::invalid_argument, "invalid AST"));
vlog("ASTWorker running {0} on version {2} of {1}", Name, FileName,
FileInputs.Version);
Action(InputsAndAST{FileInputs, **AST});
diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp
index 11d70b550642..c099a30c4d34 100644
--- a/clang-tools-extra/clangd/index/Serialization.cpp
+++ b/clang-tools-extra/clangd/index/Serialization.cpp
@@ -25,10 +25,6 @@
namespace clang {
namespace clangd {
namespace {
-llvm::Error makeError(const llvm::Twine &Msg) {
- return llvm::make_error<llvm::StringError>(Msg,
- llvm::inconvertibleErrorCode());
-}
// IO PRIMITIVES
// We use little-endian 32 bit ints, sometimes with variable-length encoding.
@@ -199,7 +195,7 @@ llvm::Expected<StringTableIn> readStringTable(llvm::StringRef Data) {
Reader R(Data);
size_t UncompressedSize = R.consume32();
if (R.err())
- return makeError("Truncated string table");
+ return error("Truncated string table");
llvm::StringRef Uncompressed;
llvm::SmallString<1> UncompressedStorage;
@@ -218,12 +214,12 @@ llvm::Expected<StringTableIn> readStringTable(llvm::StringRef Data) {
for (Reader R(Uncompressed); !R.eof();) {
auto Len = R.rest().find(0);
if (Len == llvm::StringRef::npos)
- return makeError("Bad string table: not null terminated");
+ return error("Bad string table: not null terminated");
Table.Strings.push_back(Saver.save(R.consume(Len)));
R.consume8();
}
if (R.err())
- return makeError("Truncated string table");
+ return error("Truncated string table");
return std::move(Table);
}
@@ -426,24 +422,23 @@ llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) {
if (!RIFF)
return RIFF.takeError();
if (RIFF->Type != riff::fourCC("CdIx"))
- return makeError("wrong RIFF filetype: " + riff::fourCCStr(RIFF->Type));
+ return error("wrong RIFF filetype: {0}", riff::fourCCStr(RIFF->Type));
llvm::StringMap<llvm::StringRef> Chunks;
for (const auto &Chunk : RIFF->Chunks)
Chunks.try_emplace(llvm::StringRef(Chunk.ID.data(), Chunk.ID.size()),
Chunk.Data);
if (!Chunks.count("meta"))
- return makeError("missing meta chunk");
+ return error("missing meta chunk");
Reader Meta(Chunks.lookup("meta"));
auto SeenVersion = Meta.consume32();
if (SeenVersion != Version)
- return makeError("wrong version: want " + llvm::Twine(Version) + ", got " +
- llvm::Twine(SeenVersion));
+ return error("wrong version: want {0}, got {1}", Version, SeenVersion);
// meta chunk is checked above, as we prefer the "version mismatch" error.
for (llvm::StringRef RequiredChunk : {"stri"})
if (!Chunks.count(RequiredChunk))
- return makeError("missing required chunk " + RequiredChunk);
+ return error("missing required chunk {0}", RequiredChunk);
auto Strings = readStringTable(Chunks.lookup("stri"));
if (!Strings)
@@ -464,7 +459,7 @@ llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) {
Include = Result.Sources->try_emplace(Include).first->getKey();
}
if (SrcsReader.err())
- return makeError("malformed or truncated include uri");
+ return error("malformed or truncated include uri");
}
if (Chunks.count("symb")) {
@@ -473,7 +468,7 @@ llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) {
while (!SymbolReader.eof())
Symbols.insert(readSymbol(SymbolReader, Strings->Strings));
if (SymbolReader.err())
- return makeError("malformed or truncated symbol");
+ return error("malformed or truncated symbol");
Result.Symbols = std::move(Symbols).build();
}
if (Chunks.count("refs")) {
@@ -485,7 +480,7 @@ llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) {
Refs.insert(RefsBundle.first, Ref);
}
if (RefsReader.err())
- return makeError("malformed or truncated refs");
+ return error("malformed or truncated refs");
Result.Refs = std::move(Refs).build();
}
if (Chunks.count("rela")) {
@@ -496,13 +491,13 @@ llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) {
Relations.insert(Relation);
}
if (RelationsReader.err())
- return makeError("malformed or truncated relations");
+ return error("malformed or truncated relations");
Result.Relations = std::move(Relations).build();
}
if (Chunks.count("cmdl")) {
Reader CmdReader(Chunks.lookup("cmdl"));
if (CmdReader.err())
- return makeError("malformed or truncated commandline section");
+ return error("malformed or truncated commandline section");
InternedCompileCommand Cmd =
readCompileCommand(CmdReader, Strings->Strings);
Result.Cmd.emplace();
@@ -660,8 +655,8 @@ llvm::Expected<IndexFileIn> readIndexFile(llvm::StringRef Data) {
} else if (auto YAMLContents = readYAML(Data)) {
return std::move(*YAMLContents);
} else {
- return makeError("Not a RIFF file and failed to parse as YAML: " +
- llvm::toString(YAMLContents.takeError()));
+ return error("Not a RIFF file and failed to parse as YAML: {0}",
+ YAMLContents.takeError());
}
}
diff --git a/clang-tools-extra/clangd/support/Logger.cpp b/clang-tools-extra/clangd/support/Logger.cpp
index 768d2e52210b..4a5d7d63bed4 100644
--- a/clang-tools-extra/clangd/support/Logger.cpp
+++ b/clang-tools-extra/clangd/support/Logger.cpp
@@ -9,6 +9,7 @@
#include "support/Logger.h"
#include "support/Trace.h"
#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
@@ -58,5 +59,27 @@ void StreamLogger::log(Logger::Level Level,
Logs.flush();
}
+namespace {
+// Like llvm::StringError but with fewer options and no gratuitous copies.
+class SimpleStringError : public llvm::ErrorInfo<SimpleStringError> {
+ std::error_code EC;
+ std::string Message;
+
+public:
+ SimpleStringError(std::error_code EC, std::string &&Message)
+ : EC(EC), Message(std::move(Message)) {}
+ void log(llvm::raw_ostream &OS) const override { OS << Message; }
+ std::string message() const override { return Message; }
+ std::error_code convertToErrorCode() const override { return EC; }
+ static char ID;
+};
+char SimpleStringError::ID;
+
+} // namespace
+
+llvm::Error detail::error(std::error_code EC, std::string &&Msg) {
+ return llvm::make_error<SimpleStringError>(EC, std::move(Msg));
+}
+
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/support/Logger.h b/clang-tools-extra/clangd/support/Logger.h
index 72d1408bdc77..0674671aa8e1 100644
--- a/clang-tools-extra/clangd/support/Logger.h
+++ b/clang-tools-extra/clangd/support/Logger.h
@@ -45,6 +45,8 @@ 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))...));
}
+
+llvm::Error error(std::error_code, std::string &&);
} // namespace detail
// Clangd logging functions write to a global logger set by LoggingSession.
@@ -67,6 +69,30 @@ template <typename... Ts> void log(const char *Fmt, Ts &&... Vals) {
template <typename... Ts> void vlog(const char *Fmt, Ts &&... Vals) {
detail::log(Logger::Verbose, Fmt, std::forward<Ts>(Vals)...);
}
+// error() constructs an llvm::Error object, using formatv()-style arguments.
+// It is not automatically logged! (This function is a little out of place).
+// The error simply embeds the message string.
+template <typename... Ts>
+llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals) {
+ // We must render the formatv_object eagerly, while references are valid.
+ return detail::error(
+ EC, llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
+}
+// Overload with no error_code conversion, the error will be inconvertible.
+template <typename... Ts> llvm::Error error(const char *Fmt, Ts &&... Vals) {
+ return detail::error(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...).str());
+}
+// Overload to avoid formatv complexity for simple strings.
+inline llvm::Error error(std::error_code EC, std::string Msg) {
+ return detail::error(EC, std::move(Msg));
+}
+// Overload for simple strings with no error_code conversion.
+inline llvm::Error error(std::string Msg) {
+ return detail::error(llvm::inconvertibleErrorCode(), std::move(Msg));
+}
+
// dlog only logs if --debug was passed, or --debug_only=Basename.
// This level would be enabled in a targeted way when debugging.
#define dlog(...) \
diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt
index 966fa9630852..2167b5e210e2 100644
--- a/clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -62,6 +62,7 @@ add_unittest(ClangdUnitTests ClangdTests
IndexActionTests.cpp
IndexTests.cpp
JSONTransportTests.cpp
+ LoggerTests.cpp
LSPClient.cpp
ModulesTests.cpp
ParsedASTTests.cpp
diff --git a/clang-tools-extra/clangd/unittests/LoggerTests.cpp b/clang-tools-extra/clangd/unittests/LoggerTests.cpp
new file mode 100644
index 000000000000..3d2194d79090
--- /dev/null
+++ b/clang-tools-extra/clangd/unittests/LoggerTests.cpp
@@ -0,0 +1,62 @@
+//===-- LoggerTests.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "support/Logger.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+TEST(ErrorTest, Overloads) {
+ EXPECT_EQ("foo", llvm::toString(error("foo")));
+ // Inconvertible to error code when none is specified.
+ // Don't actually try to convert, it'll crash.
+ handleAllErrors(error("foo"), [&](const llvm::ErrorInfoBase &EI) {
+ EXPECT_EQ(llvm::inconvertibleErrorCode(), EI.convertToErrorCode());
+ });
+
+ EXPECT_EQ("foo 42", llvm::toString(error("foo {0}", 42)));
+ handleAllErrors(error("foo {0}", 42), [&](const llvm::ErrorInfoBase &EI) {
+ EXPECT_EQ(llvm::inconvertibleErrorCode(), EI.convertToErrorCode());
+ });
+
+ EXPECT_EQ("foo", llvm::toString(error(llvm::errc::invalid_argument, "foo")));
+ EXPECT_EQ(llvm::errc::invalid_argument,
+ llvm::errorToErrorCode(error(llvm::errc::invalid_argument, "foo")));
+
+ EXPECT_EQ("foo 42",
+ llvm::toString(error(llvm::errc::invalid_argument, "foo {0}", 42)));
+ EXPECT_EQ(llvm::errc::invalid_argument,
+ llvm::errorToErrorCode(
+ error(llvm::errc::invalid_argument, "foo {0}", 42)));
+}
+
+TEST(ErrorTest, Lifetimes) {
+ llvm::Optional<llvm::Error> Err;
+ {
+ // Check the error contains the value when error() was called.
+ std::string S = "hello, world";
+ Err = error("S={0}", llvm::StringRef(S));
+ S = "garbage";
+ }
+ EXPECT_EQ("S=hello, world", llvm::toString(std::move(*Err)));
+}
+
+TEST(ErrorTest, ConsumeError) {
+ llvm::Error Foo = error("foo");
+ llvm::Error Bar = error("bar: {0}", std::move(Foo));
+ EXPECT_EQ("bar: foo", llvm::toString(std::move(Bar)));
+ // No assert for unchecked Foo.
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
More information about the cfe-commits
mailing list