kuhnel created this revision.
kuhnel added a reviewer: sammccall.
Herald added subscribers: dexonsmith, usaxena95, kadircet, arphaman.
kuhnel requested review of this revision.
Herald added projects: LLVM, clang-tools-extra.
Herald added subscribers: cfe-commits, llvm-commits.

Since I had some fun understanding how to properly use llvm::Expected<T> I 
added some code examples that I would have liked to see when learning to use it.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105014

Files:
  clang-tools-extra/clangd/index/StdLib.cpp
  llvm/include/llvm/Support/Error.h

Index: llvm/include/llvm/Support/Error.h
===================================================================
--- llvm/include/llvm/Support/Error.h
+++ llvm/include/llvm/Support/Error.h
@@ -162,7 +162,7 @@
 
   // handleErrors needs to be able to set the Checked flag.
   template <typename... HandlerTs>
-  friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+  friend Error handleErrors(Error E, HandlerTs &&...Handlers);
 
   // Expected<T> needs to be able to steal the payload when constructed from an
   // error.
@@ -244,7 +244,7 @@
 
   /// Returns the dynamic class id of this error, or null if this is a success
   /// value.
-  const void* dynamicClassID() const {
+  const void *dynamicClassID() const {
     if (!getPtr())
       return nullptr;
     return getPtr()->dynamicClassID();
@@ -270,9 +270,8 @@
 
   ErrorInfoBase *getPtr() const {
 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
-    return reinterpret_cast<ErrorInfoBase*>(
-             reinterpret_cast<uintptr_t>(Payload) &
-             ~static_cast<uintptr_t>(0x1));
+    return reinterpret_cast<ErrorInfoBase *>(
+        reinterpret_cast<uintptr_t>(Payload) & ~static_cast<uintptr_t>(0x1));
 #else
     return Payload;
 #endif
@@ -280,10 +279,9 @@
 
   void setPtr(ErrorInfoBase *EI) {
 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
-    Payload = reinterpret_cast<ErrorInfoBase*>(
-                (reinterpret_cast<uintptr_t>(EI) &
-                 ~static_cast<uintptr_t>(0x1)) |
-                (reinterpret_cast<uintptr_t>(Payload) & 0x1));
+    Payload = reinterpret_cast<ErrorInfoBase *>(
+        (reinterpret_cast<uintptr_t>(EI) & ~static_cast<uintptr_t>(0x1)) |
+        (reinterpret_cast<uintptr_t>(Payload) & 0x1));
 #else
     Payload = EI;
 #endif
@@ -299,10 +297,9 @@
 
   void setChecked(bool V) {
 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
-    Payload = reinterpret_cast<ErrorInfoBase*>(
-                (reinterpret_cast<uintptr_t>(Payload) &
-                  ~static_cast<uintptr_t>(0x1)) |
-                  (V ? 0 : 1));
+    Payload = reinterpret_cast<ErrorInfoBase *>(
+        (reinterpret_cast<uintptr_t>(Payload) & ~static_cast<uintptr_t>(0x1)) |
+        (V ? 0 : 1));
 #endif
   }
 
@@ -333,7 +330,7 @@
 
 /// Make a Error instance representing failure using the given error info
 /// type.
-template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
+template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&...Args) {
   return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
 }
 
@@ -366,7 +363,7 @@
   // handleErrors needs to be able to iterate the payload list of an
   // ErrorList.
   template <typename... HandlerTs>
-  friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+  friend Error handleErrors(Error E, HandlerTs &&...Handlers);
 
   // joinErrors is implemented in terms of join.
   friend Error joinErrors(Error, Error);
@@ -436,6 +433,49 @@
 /// Error cannot be copied, this class replaces getError() with
 /// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
 /// error class type.
+///
+/// Example usage of 'Expected<T>' as a return type:
+///
+///   @code{.cpp}
+///     Expected<int> myDivide(int A, int B) {
+///       if (B == 0) {
+///         // return an Error
+///         return error("B must not be zero!");
+///       }
+///       // return an integer
+///       return A / B;
+///     }
+///   @endcode
+///
+///   Checking the results of to a function returning 'Expected<T>':
+///   @code{.cpp}
+///     auto Result = myDivide(X,Y);
+///     if (!Result) {
+///       auto Error = Result.takeError();
+///       // handle the error case here
+///     } else {
+///       // handle good case here
+///     }
+///
+///   @endcode
+///
+///  Unit-testing a function returning an 'Expceted<T>':
+///   @code{.cpp}
+///   TEST(MyTests, ExpectedDemo) {
+///     auto Passed = myDivide(10, 5);
+///     // check this call has passed, this also prints the error message
+///     // if the function returns an Error
+///     ASSERT_TRUE((bool)Passed) << llvm::toString(Passed.takeError());
+///     // checked the returned value
+///     ASSERT_EQ(2, *Passed);
+///
+///     auto Failed = myDivide(1, 0);
+///     ASSERT_FALSE((bool)Failed);
+///     // make sure Failed.takeError() does not get remove by the optimizer
+///     std::cout << "Expected failure: " << llvm::toString(Failed.takeError());
+///   }
+///   @endcode
+
 template <class T> class LLVM_NODISCARD Expected {
   template <class T1> friend class ExpectedAsOutParameter;
   template <class OtherT> friend class Expected;
@@ -462,7 +502,8 @@
       : HasError(true)
 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
         // Expected is unchecked upon construction in Debug builds.
-        , Unchecked(true)
+        ,
+        Unchecked(true)
 #endif
   {
     assert(Err && "Cannot create Expected<T> from Error success value.");
@@ -764,7 +805,7 @@
 ///   Bar &X = cantFail(foo(false));
 ///   @endcode
 template <typename T>
-T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) {
+T &cantFail(Expected<T &> ValOrErr, const char *Msg = nullptr) {
   if (ValOrErr)
     return *ValOrErr;
   else {
@@ -785,8 +826,8 @@
 /// ErrorInfo types.
 template <typename HandlerT>
 class ErrorHandlerTraits
-    : public ErrorHandlerTraits<decltype(
-          &std::remove_reference<HandlerT>::type::operator())> {};
+    : public ErrorHandlerTraits<
+          decltype(&std::remove_reference<HandlerT>::type::operator())> {};
 
 // Specialization functions of the form 'Error (const ErrT&)'.
 template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
@@ -888,7 +929,7 @@
 
 template <typename HandlerT, typename... HandlerTs>
 Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
-                      HandlerT &&Handler, HandlerTs &&... Handlers) {
+                      HandlerT &&Handler, HandlerTs &&...Handlers) {
   if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
     return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
                                                std::move(Payload));
@@ -903,7 +944,7 @@
 /// or returned. If you intend to handle all errors use handleAllErrors
 /// (which returns void, and will abort() on unhandled errors) instead.
 template <typename... HandlerTs>
-Error handleErrors(Error E, HandlerTs &&... Hs) {
+Error handleErrors(Error E, HandlerTs &&...Hs) {
   if (!E)
     return Error::success();
 
@@ -926,15 +967,13 @@
 /// *must* be handled by the given handlers (i.e. there must be no remaining
 /// errors after running the handlers, or llvm_unreachable is called).
 template <typename... HandlerTs>
-void handleAllErrors(Error E, HandlerTs &&... Handlers) {
+void handleAllErrors(Error E, HandlerTs &&...Handlers) {
   cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...));
 }
 
 /// Check that E is a non-error, then drop it.
 /// If E is an error, llvm_unreachable will be called.
-inline void handleAllErrors(Error E) {
-  cantFail(std::move(E));
-}
+inline void handleAllErrors(Error E) { cantFail(std::move(E)); }
 
 /// Handle any errors (if present) in an Expected<T>, then try a recovery path.
 ///
@@ -962,7 +1001,7 @@
 ///   @endcode
 template <typename T, typename RecoveryFtor, typename... HandlerTs>
 Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath,
-                           HandlerTs &&... Handlers) {
+                           HandlerTs &&...Handlers) {
   if (ValOrErr)
     return ValOrErr;
 
@@ -1078,11 +1117,9 @@
 /// Helper for Expected<T>s used as out-parameters.
 ///
 /// See ErrorAsOutParameter.
-template <typename T>
-class ExpectedAsOutParameter {
+template <typename T> class ExpectedAsOutParameter {
 public:
-  ExpectedAsOutParameter(Expected<T> *ValOrErr)
-    : ValOrErr(ValOrErr) {
+  ExpectedAsOutParameter(Expected<T> *ValOrErr) : ValOrErr(ValOrErr) {
     if (ValOrErr)
       (void)!!*ValOrErr;
   }
@@ -1126,7 +1163,7 @@
 /// It should only be used in this situation, and should never be used where a
 /// sensible conversion to std::error_code is available, as attempts to convert
 /// to/from this error will result in a fatal error. (i.e. it is a programmatic
-///error to try to convert such a value).
+/// error to try to convert such a value).
 std::error_code inconvertibleErrorCode();
 
 /// Helper for converting an std::error_code to a Error.
@@ -1200,7 +1237,7 @@
 /// Create formatted StringError object.
 template <typename... Ts>
 inline Error createStringError(std::error_code EC, char const *Fmt,
-                               const Ts &... Vals) {
+                               const Ts &...Vals) {
   std::string Buffer;
   raw_string_ostream Stream(Buffer);
   Stream << format(Fmt, Vals...);
@@ -1215,7 +1252,7 @@
 
 template <typename... Ts>
 inline Error createStringError(std::errc EC, char const *Fmt,
-                               const Ts &... Vals) {
+                               const Ts &...Vals) {
   return createStringError(std::make_error_code(EC), Fmt, Vals...);
 }
 
@@ -1285,7 +1322,7 @@
   return FileError::build(F, Optional<size_t>(Line), std::move(E));
 }
 
-/// Concatenate a source file path and/or name with a std::error_code 
+/// Concatenate a source file path and/or name with a std::error_code
 /// to form an Error object.
 inline Error createFileError(const Twine &F, std::error_code EC) {
   return createFileError(F, errorCodeToError(EC));
@@ -1328,9 +1365,9 @@
     return std::move(*E);
   }
 
-  /// Check E. If it's in a success state then return the contained reference. If
-  /// it's in a failure state log the error(s) and exit.
-  template <typename T> T& operator()(Expected<T&> &&E) const {
+  /// Check E. If it's in a success state then return the contained reference.
+  /// If it's in a failure state log the error(s) and exit.
+  template <typename T> T &operator()(Expected<T &> &&E) const {
     checkError(E.takeError());
     return *E;
   }
Index: clang-tools-extra/clangd/index/StdLib.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/index/StdLib.cpp
@@ -0,0 +1,111 @@
+#include "StdLib.h"
+#include <memory>
+#include <set>
+
+#include "Compiler.h"
+#include "Headers.h"
+#include "SymbolCollector.h"
+#include "index/IndexAction.h"
+#include "index/Serialization.h"
+#include "support/Logger.h"
+#include "support/ThreadsafeFS.h"
+#include "support/Trace.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
+namespace clang {
+namespace clangd {
+
+std::string StandardLibraryIndex::generateIncludeHeader() {
+  std::string Includes;
+  // gather all the known STL headers in a set for depulication
+  std::set<std::string> Headers;
+
+#define SYMBOL(Name, NameSpace, Header) Headers.insert(#Header);
+#include "StdSymbolMap.inc"
+#undef SYMBOL
+
+  for (auto Header : Headers) {
+    Includes += "#include " + Header + "\n";
+  }
+  return Includes;
+}
+namespace {
+/* Wrapper around llvm::vfs::InMemoryFileSystem */
+class MemTFS : public ThreadsafeFS {
+
+private:
+  const llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS;
+
+public:
+  MemTFS(llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> const FS)
+      : FS(FS){};
+
+  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> viewImpl() const override {
+    return FS;
+  }
+};
+} // namespace
+
+Expected<std::unique_ptr<SymbolIndex>>
+StandardLibraryIndex::indexHeaders(const std::string &HeaderSources) {
+  const auto *StdLibHeaderFileName = "stdlibheaders.h";
+  auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+  auto Now =
+      std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+  FS->addFile(
+      StdLibHeaderFileName, Now,
+      llvm::MemoryBuffer::getMemBufferCopy(HeaderSources, "stdlibheaders.h"));
+
+  ParseInputs Inputs;
+  MemTFS TFS(FS);
+  Inputs.TFS = &TFS;
+  // TODO: can we get a real compile command from somewhere?
+  Inputs.CompileCommand = tooling::CompileCommand();
+  IgnoreDiagnostics IgnoreDiags;
+
+  auto CI = buildCompilerInvocation(Inputs, IgnoreDiags);
+  if (!CI)
+    return error("Couldn't build compiler invocation");
+
+  auto Buffer = FS->getBufferForFile(StdLibHeaderFileName);
+  if (!Buffer)
+    return error("Could not read file from InMemoryFileSystem");
+  auto Clang = prepareCompilerInstance(std::move(CI), /*Preamble=*/nullptr,
+                                       std::move(*Buffer), FS, IgnoreDiags);
+  if (!Clang)
+    return error("Couldn't build compiler instance");
+
+  SymbolCollector::Options IndexOpts;
+  SymbolSlab TmpSymolSlab;
+  RefSlab TmpRefSlab;
+  RelationSlab TmpRelationSlab;
+  auto Action = createStaticIndexingAction(
+      IndexOpts, [&](SymbolSlab S) { TmpSymolSlab = std::move(S); },
+      [&](RefSlab R) { TmpRefSlab = std::move(R); },
+      [&](RelationSlab R) { TmpRelationSlab = std::move(R); },
+      /*IncludeGraphCallback=*/nullptr);
+  assert(!TmpSymolSlab.empty() && !TmpRefSlab.empty() &&
+         !TmpRelationSlab.empty() && "Symbols, Refs and Sources must be set.");
+  auto Index = MemIndex::build(std::move(TmpSymolSlab), std::move(TmpRefSlab),
+                               std::move(TmpRelationSlab));
+
+  const FrontendInputFile &Input = Clang->getFrontendOpts().Inputs.front();
+  if (!Action->BeginSourceFile(*Clang, Input))
+    return error("BeginSourceFile() failed");
+  if (auto Err = Action->Execute())
+    return std::move(Err);
+  Action->EndSourceFile();
+
+  // TODO: add tracing information on index sizes
+
+  bool HadErrors = Clang->hasDiagnostics() &&
+                   Clang->getDiagnostics().hasUncompilableErrorOccurred();
+  if (HadErrors) {
+    log("Failed to compile standard librarx index, index may be incomplete");
+  }
+
+  return Index;
+}
+} // namespace clangd
+} // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to