Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===- PartialDiagnostic.h - Diagnostic "closures" --------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. /// \file
  10. /// Implements a partial diagnostic that can be emitted anwyhere
  11. /// in a DiagnosticBuilder stream.
  12. //
  13. //===----------------------------------------------------------------------===//
  14.  
  15. #ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
  16. #define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
  17.  
  18. #include "clang/Basic/Diagnostic.h"
  19. #include "clang/Basic/LLVM.h"
  20. #include "clang/Basic/SourceLocation.h"
  21. #include "llvm/ADT/SmallVector.h"
  22. #include "llvm/ADT/StringRef.h"
  23. #include <cassert>
  24. #include <cstdint>
  25. #include <string>
  26. #include <type_traits>
  27. #include <utility>
  28.  
  29. namespace clang {
  30.  
  31. class PartialDiagnostic : public StreamingDiagnostic {
  32. private:
  33.   // NOTE: Sema assumes that PartialDiagnostic is location-invariant
  34.   // in the sense that its bits can be safely memcpy'ed and destructed
  35.   // in the new location.
  36.  
  37.   /// The diagnostic ID.
  38.   mutable unsigned DiagID = 0;
  39. public:
  40.   struct NullDiagnostic {};
  41.  
  42.   /// Create a null partial diagnostic, which cannot carry a payload,
  43.   /// and only exists to be swapped with a real partial diagnostic.
  44.   PartialDiagnostic(NullDiagnostic) {}
  45.  
  46.   PartialDiagnostic(unsigned DiagID, DiagStorageAllocator &Allocator_)
  47.       : StreamingDiagnostic(Allocator_), DiagID(DiagID) {}
  48.  
  49.   PartialDiagnostic(const PartialDiagnostic &Other)
  50.       : StreamingDiagnostic(), DiagID(Other.DiagID) {
  51.     Allocator = Other.Allocator;
  52.     if (Other.DiagStorage) {
  53.       DiagStorage = getStorage();
  54.       *DiagStorage = *Other.DiagStorage;
  55.     }
  56.   }
  57.  
  58.   template <typename T> const PartialDiagnostic &operator<<(const T &V) const {
  59.     const StreamingDiagnostic &DB = *this;
  60.     DB << V;
  61.     return *this;
  62.   }
  63.  
  64.   // It is necessary to limit this to rvalue reference to avoid calling this
  65.   // function with a bitfield lvalue argument since non-const reference to
  66.   // bitfield is not allowed.
  67.   template <typename T,
  68.             typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
  69.   const PartialDiagnostic &operator<<(T &&V) const {
  70.     const StreamingDiagnostic &DB = *this;
  71.     DB << std::move(V);
  72.     return *this;
  73.   }
  74.  
  75.   PartialDiagnostic(PartialDiagnostic &&Other) : DiagID(Other.DiagID) {
  76.     Allocator = Other.Allocator;
  77.     DiagStorage = Other.DiagStorage;
  78.     Other.DiagStorage = nullptr;
  79.   }
  80.  
  81.   PartialDiagnostic(const PartialDiagnostic &Other,
  82.                     DiagnosticStorage *DiagStorage_)
  83.       : DiagID(Other.DiagID) {
  84.     Allocator = reinterpret_cast<DiagStorageAllocator *>(~uintptr_t(0));
  85.     DiagStorage = DiagStorage_;
  86.     if (Other.DiagStorage)
  87.       *this->DiagStorage = *Other.DiagStorage;
  88.   }
  89.  
  90.   PartialDiagnostic(const Diagnostic &Other, DiagStorageAllocator &Allocator_)
  91.       : DiagID(Other.getID()) {
  92.     Allocator = &Allocator_;
  93.     // Copy arguments.
  94.     for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
  95.       if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
  96.         AddString(Other.getArgStdStr(I));
  97.       else
  98.         AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
  99.     }
  100.  
  101.     // Copy source ranges.
  102.     for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I)
  103.       AddSourceRange(Other.getRange(I));
  104.  
  105.     // Copy fix-its.
  106.     for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I)
  107.       AddFixItHint(Other.getFixItHint(I));
  108.   }
  109.  
  110.   PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
  111.     DiagID = Other.DiagID;
  112.     if (Other.DiagStorage) {
  113.       if (!DiagStorage)
  114.         DiagStorage = getStorage();
  115.  
  116.       *DiagStorage = *Other.DiagStorage;
  117.     } else {
  118.       freeStorage();
  119.     }
  120.  
  121.     return *this;
  122.   }
  123.  
  124.   PartialDiagnostic &operator=(PartialDiagnostic &&Other) {
  125.     freeStorage();
  126.  
  127.     DiagID = Other.DiagID;
  128.     DiagStorage = Other.DiagStorage;
  129.     Allocator = Other.Allocator;
  130.  
  131.     Other.DiagStorage = nullptr;
  132.     return *this;
  133.   }
  134.  
  135.   void swap(PartialDiagnostic &PD) {
  136.     std::swap(DiagID, PD.DiagID);
  137.     std::swap(DiagStorage, PD.DiagStorage);
  138.     std::swap(Allocator, PD.Allocator);
  139.   }
  140.  
  141.   unsigned getDiagID() const { return DiagID; }
  142.   void setDiagID(unsigned ID) { DiagID = ID; }
  143.  
  144.   void Emit(const DiagnosticBuilder &DB) const {
  145.     if (!DiagStorage)
  146.       return;
  147.  
  148.     // Add all arguments.
  149.     for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
  150.       if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
  151.             == DiagnosticsEngine::ak_std_string)
  152.         DB.AddString(DiagStorage->DiagArgumentsStr[i]);
  153.       else
  154.         DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
  155.             (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
  156.     }
  157.  
  158.     // Add all ranges.
  159.     for (const CharSourceRange &Range : DiagStorage->DiagRanges)
  160.       DB.AddSourceRange(Range);
  161.  
  162.     // Add all fix-its.
  163.     for (const FixItHint &Fix : DiagStorage->FixItHints)
  164.       DB.AddFixItHint(Fix);
  165.   }
  166.  
  167.   void EmitToString(DiagnosticsEngine &Diags,
  168.                     SmallVectorImpl<char> &Buf) const {
  169.     // FIXME: It should be possible to render a diagnostic to a string without
  170.     //        messing with the state of the diagnostics engine.
  171.     DiagnosticBuilder DB(Diags.Report(getDiagID()));
  172.     Emit(DB);
  173.     Diagnostic(&Diags).FormatDiagnostic(Buf);
  174.     DB.Clear();
  175.     Diags.Clear();
  176.   }
  177.  
  178.   /// Clear out this partial diagnostic, giving it a new diagnostic ID
  179.   /// and removing all of its arguments, ranges, and fix-it hints.
  180.   void Reset(unsigned DiagID = 0) {
  181.     this->DiagID = DiagID;
  182.     freeStorage();
  183.   }
  184.  
  185.   bool hasStorage() const { return DiagStorage != nullptr; }
  186.  
  187.   /// Retrieve the string argument at the given index.
  188.   StringRef getStringArg(unsigned I) {
  189.     assert(DiagStorage && "No diagnostic storage?");
  190.     assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args");
  191.     assert(DiagStorage->DiagArgumentsKind[I]
  192.              == DiagnosticsEngine::ak_std_string && "Not a string arg");
  193.     return DiagStorage->DiagArgumentsStr[I];
  194.   }
  195. };
  196.  
  197. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
  198.                                            const PartialDiagnostic &PD) {
  199.   PD.Emit(DB);
  200.   return DB;
  201. }
  202.  
  203. /// A partial diagnostic along with the source location where this
  204. /// diagnostic occurs.
  205. using PartialDiagnosticAt = std::pair<SourceLocation, PartialDiagnostic>;
  206.  
  207. } // namespace clang
  208.  
  209. #endif // LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
  210.